Micron Document
rns.moscow πŸŸ₯ [git]

Node / public / RNode_Flasher / files / htdocs / index.html

Displaying Raw β€’ Download

htdocs/index.html 8d64759ef727bd9bee11859fcb348dafd96e1d99 (8d64759e) Text, 212.48 KB

Tff7b72<!DOCTYPE html>
Tb4b4b4<Tff7b72html Te6edf3langTff7b72=Ta5d6ff"en"Tb4b4b4>
Tb4b4b4<Tff7b72headTb4b4b4>
Tb4b4b4<Tff7b72meta Te6edf3charsetTff7b72=Ta5d6ff"UTF-8"Tb4b4b4>
Tb4b4b4<Tff7b72meta Te6edf3nameTff7b72=Ta5d6ff"viewport" Te6edf3contentTff7b72=Ta5d6ff"width=device-width, initial-scale=1.0"Tb4b4b4>
Tb4b4b4<Tff7b72meta Te6edf3nameTff7b72=Ta5d6ff"description" Te6edf3contentTff7b72=Ta5d6ff"RNode Flasher β€” ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠ° ESP32 RNode-устройств прямо Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅."Tb4b4b4>
Tb4b4b4<Tff7b72titleTb4b4b4>RNode Flasher β€” RNS.MOSCOWTb4b4b4<Tb4b4b4/Tff7b72titleTb4b4b4>
Tb4b4b4<Tff7b72link Te6edf3relTff7b72=Ta5d6ff"preconnect" Te6edf3hrefTff7b72=Ta5d6ff"https://fonts.googleapis.com"Tb4b4b4>
Tb4b4b4<Tff7b72link Te6edf3relTff7b72=Ta5d6ff"preconnect" Te6edf3hrefTff7b72=Ta5d6ff"https://fonts.gstatic.com" Te6edf3crossoriginTb4b4b4>
Tb4b4b4<Tff7b72link Te6edf3hrefTff7b72=Ta5d6ff"https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,300;0,400;0,500;0,700;1,400&display=swap" Te6edf3relTff7b72=Ta5d6ff"stylesheet"Tb4b4b4>
Tb4b4b4<Tff7b72link Te6edf3relTff7b72=Ta5d6ff"icon" Te6edf3hrefTff7b72=Ta5d6ff"favicon.ico"Tb4b4b4>
Tb4b4b4<Tff7b72link Te6edf3relTff7b72=Ta5d6ff"stylesheet" Te6edf3hrefTff7b72=Ta5d6ff"style.css"Tb4b4b4>
Tb4b4b4<Tff7b72script Te6edf3srcTff7b72=Ta5d6ff"js/i18n.js?v=20260711"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>
Tb4b4b4<Tff7b72script Te6edf3srcTff7b72=Ta5d6ff"js/zip.min.js"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>
Tb4b4b4<Tff7b72script Te6edf3srcTff7b72=Ta5d6ff"js/crypto-js@3.9.1-1/core.js"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>
Tb4b4b4<Tff7b72script Te6edf3srcTff7b72=Ta5d6ff"js/crypto-js@3.9.1-1/md5.js"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>
Tb4b4b4<Tff7b72script Te6edf3srcTff7b72=Ta5d6ff"js/vue@3.4.26/dist/vue.global.prod.js"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>
Tb4b4b4<Tff7b72script Te6edf3srcTff7b72=Ta5d6ff"js/nrf52_dfu_flasher.js"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>
Tb4b4b4<Tff7b72script Te6edf3srcTff7b72=Ta5d6ff"js/nordic_dfu_flasher.js"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72headTb4b4b4>
Tb4b4b4<Tff7b72bodyTb4b4b4>

Tb4b4b4<Tff7b72scriptTb4b4b4>
T8b949e// ── Brand config ─────────────────────────────────────────────────
T8b949e// One codebase, multiple skins. Flip BRAND_ID before rsyncing htdocs/ to a
T8b949e// differently-branded deployment β€” it is not user-selectable at runtime.
Tffa657windowTb4b4b4.Te6edf3BRAND_ID Tff7b72= Ta5d6ff'rns'Tb4b4b4; T8b949e// 'rns' | 'aetherlab'
Tffa657windowTb4b4b4.Te6edf3BRANDS Tff7b72= Tb4b4b4{
Te6edf3rnsTff7b72: Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'RNS.MOSCOW'Tb4b4b4,
Te6edf3titleTff7b72: Ta5d6ff'RNode Flasher β€” RNS.MOSCOW'Tb4b4b4,
Te6edf3descriptionTff7b72: Ta5d6ff'RNode Flasher β€” ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠ° ESP32 RNode-устройств прямо Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅.'Tb4b4b4,
Te6edf3homeUrlTff7b72: Ta5d6ff'https://rns.moscow'Tb4b4b4,
Te6edf3docsUrlTff7b72: Ta5d6ff'https://docs.rns.moscow'Tb4b4b4,
Te6edf3gitUrlTff7b72: Ta5d6ff'https://git.rns.moscow/explore/repos'Tb4b4b4,
Te6edf3statsUrlTff7b72: Ta5d6ff'/stats/'Tb4b4b4,
Te6edf3firmwareUrlTff7b72: Ta5d6ff'https://flasher.rns.moscow/firmware/'Tb4b4b4,
Te6edf3sourceUrlTff7b72: Ta5d6ff'https://git.rns.moscow/explore/repos'Tb4b4b4,
Te6edf3altLangTff7b72: Ta5d6ff'ru'Tb4b4b4, T8b949e// secondary language shown next to EN in the nav toggle
T8b949e// Sibling deployments of this same codebase: USB flashing needs a
T8b949e// secure context (Web Serial), WebSocket needs a non-secure one (else
T8b949e// the browser blocks ws:// as mixed content) β€” so switching transport
T8b949e// means handing off to the other origin, not an in-page toggle.
Te6edf3usbUrlTff7b72: Ta5d6ff'https://flasher.rns.moscow/'Tb4b4b4,
Te6edf3wsUrlTff7b72: Ta5d6ff'http://ws.rns.moscow/'Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3aetherlabTff7b72: Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'AETHERLAB'Tb4b4b4,
Te6edf3titleTff7b72: Ta5d6ff'RNode Flasher β€” Aetherlab'Tb4b4b4,
Te6edf3descriptionTff7b72: Ta5d6ff'RNode Flasher β€” flash ESP32 RNode devices directly from your browser.'Tb4b4b4,
T8b949e// Links below are left unset (hidden in the nav/footer) until this
T8b949e// deployment has real destinations for them β€” fill in and redeploy.
Te6edf3homeUrlTff7b72: Tff7b72nullTb4b4b4,
Te6edf3docsUrlTff7b72: Tff7b72nullTb4b4b4,
Te6edf3gitUrlTff7b72: Tff7b72nullTb4b4b4,
Te6edf3statsUrlTff7b72: Tff7b72nullTb4b4b4,
Te6edf3firmwareUrlTff7b72: Tff7b72nullTb4b4b4,
Te6edf3sourceUrlTff7b72: Tff7b72nullTb4b4b4,
Te6edf3altLangTff7b72: Ta5d6ff'bg'Tb4b4b4,
Te6edf3usbUrlTff7b72: Tff7b72nullTb4b4b4,
Te6edf3wsUrlTff7b72: Tff7b72nullTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4;
Tffa657documentTb4b4b4.Te6edf3documentElementTb4b4b4.Te6edf3setAttributeTb4b4b4(Ta5d6ff'data-brand'Tb4b4b4, Tffa657windowTb4b4b4.Te6edf3BRAND_IDTb4b4b4)Tb4b4b4;
Tb4b4b4(Tff7b72functionTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72var Te6edf3brand Tff7b72= Tffa657windowTb4b4b4.Te6edf3BRANDSTb4b4b4[Tffa657windowTb4b4b4.Te6edf3BRAND_IDTb4b4b4]Tb4b4b4;
Tffa657documentTb4b4b4.Te6edf3title Tff7b72= Te6edf3brandTb4b4b4.Te6edf3titleTb4b4b4;
Tff7b72var Te6edf3meta Tff7b72= Tffa657documentTb4b4b4.Te6edf3querySelectorTb4b4b4(Ta5d6ff'meta[name="description"]'Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3metaTb4b4b4) Te6edf3metaTb4b4b4.Te6edf3setAttributeTb4b4b4(Ta5d6ff'content'Tb4b4b4, Te6edf3brandTb4b4b4.Te6edf3descriptionTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>

Tb4b4b4<Tff7b72script Te6edf3typeTff7b72=Ta5d6ff"module"Tb4b4b4>
Tff7b72import Tb4b4b4{ Te6edf3serial Tb4b4b4} Tff7b72from Ta5d6ff"./js/web-serial-polyfill@1.0.15/dist/serial.js"Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3navigatorTb4b4b4.Te6edf3serial Tff7b72&& Te6edf3navigatorTb4b4b4.Te6edf3usbTb4b4b4) Te6edf3navigatorTb4b4b4.Te6edf3serial Tff7b72= Te6edf3serialTb4b4b4;
Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>
Tb4b4b4<Tff7b72script Te6edf3typeTff7b72=Ta5d6ff"module"Tb4b4b4>
Tff7b72import Tb4b4b4{ Te6edf3ESPLoaderTb4b4b4, Te6edf3Transport Tb4b4b4} Tff7b72from Ta5d6ff"./js/esptool-js@0.6.0/bundle.js"Tb4b4b4;
Tffa657windowTb4b4b4.Te6edf3ESPLoader Tff7b72= Te6edf3ESPLoaderTb4b4b4;
Tffa657windowTb4b4b4.Te6edf3Transport Tff7b72= Te6edf3TransportTb4b4b4;
Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3idTff7b72=Ta5d6ff"app"Tb4b4b4>

Tb4b4b4<Tff7b72nav Te6edf3idTff7b72=Ta5d6ff"navbar" Te6edf3:classTff7b72=Ta5d6ff"{ scrolled: scrolled }"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"nav-inner"Tb4b4b4>
Tb4b4b4<Tff7b72a Te6edf3:hrefTff7b72=Ta5d6ff"brand.homeUrl" Te6edf3classTff7b72=Ta5d6ff"nav-logo"Tb4b4b4>
Tb4b4b4<Tff7b72img Te6edf3v-ifTff7b72=Ta5d6ff"brandId === 'rns'" Te6edf3classTff7b72=Ta5d6ff"logo-icon" Te6edf3srcTff7b72=Ta5d6ff"reticulum_logo_512.png" Te6edf3widthTff7b72=Ta5d6ff"28" Te6edf3heightTff7b72=Ta5d6ff"28" Te6edf3altTff7b72=Ta5d6ff"RNS"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"brandId === 'rns'" Te6edf3classTff7b72=Ta5d6ff"logo-text"Tb4b4b4>{{ brand.name }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72svg Te6edf3v-ifTff7b72=Ta5d6ff"brandId === 'aetherlab'" Te6edf3classTff7b72=Ta5d6ff"logo-aether" Te6edf3viewBoxTff7b72=Ta5d6ff"0 0 1866 404" Te6edf3roleTff7b72=Ta5d6ff"img" Te6edf3aria-labelTff7b72=Ta5d6ff"Aetherlab"Tb4b4b4>
Tb4b4b4<Tff7b72g Te6edf3fillTff7b72=Ta5d6ff"currentColor" Te6edf3transformTff7b72=Ta5d6ff"translate(0,404) scale(0.1,-0.1)"Tb4b4b4>Tb4b4b4<Tff7b72path Te6edf3dTff7b72=Ta5d6ff"M8338 2253 l-484 -1458 -737 -3 c-405 -1 -737 1 -737 5 0 5 73 231 161 504 l162 497 171 5 c189 5 266 21 386 80 97 47 204 158 259 267 l42 85 -349 3 -350 2 184 553 c101 303 184 553 184 554 0 2 -121 3 -269 3 l-269 0 -48 -87 c-143 -266 -303 -503 -422 -627 -157 -162 -431 -305 -738 -385 l-41 -11 -81 -213 c-45 -117 -82 -216 -82 -220 0 -4 97 -7 215 -7 118 0 215 -3 215 -7 0 -5 -75 -232 -166 -505 l-166 -498 -1121 0 c-731 0 -1144 4 -1186 11 -168 27 -253 113 -238 241 4 27 61 209 128 404 l122 354 304 0 305 0 -151 -295 c-83 -162 -151 -297 -151 -300 0 -3 201 -5 447 -5 l446 0 63 35 c130 73 214 177 249 310 30 117 12 277 -42 377 -61 113 -206 212 -377 258 -199 55 -153 53 -1411 57 -804 3 -1206 1 -1284 -7 -404 -39 -744 -199 -975 -459 -187 -210 -276 -482 -263 -798 8 -214 65 -352 202 -489 88 -89 191 -148 315 -181 101 -27 328 -24 440 6 164 44 310 126 436 248 l71 68 12 -58 c15 -73 68 -135 144 -167 118 -51 108 -51 1623 -48 l1409 3 76 22 c154 44 262 118 337 234 l39 60 5 -66 c7 -87 44 -148 116 -191 98 -59 95 -59 1032 -59 854 0 855 0 940 22 113 30 212 80 282 143 l56 50 -25 -82 c-14 -45 -29 -92 -34 -105 -5 -14 -9 -27 -9 -29 0 -3 152 -4 338 -2 323 3 340 4 402 26 36 13 90 39 121 58 30 18 303 238 605 488 302 250 550 451 552 446 2 -5 -46 -159 -107 -342 -117 -354 -134 -433 -112 -515 14 -52 52 -98 100 -122 78 -40 128 -42 846 -39 682 4 691 4 764 26 212 65 379 204 430 360 13 38 31 57 31 32 0 -5 30 -41 66 -80 147 -155 347 -247 649 -298 231 -39 367 -43 1320 -40 904 3 911 4 990 26 215 59 374 186 441 352 l23 55 188 5 c185 5 189 6 254 36 110 52 114 60 300 540 l166 429 293 3 c232 2 291 0 288 -10 -3 -7 -79 -233 -168 -503 -161 -484 -163 -491 -164 -580 -1 -157 54 -255 171 -308 103 -46 144 -48 818 -45 630 3 630 3 700 27 190 63 340 179 383 294 12 32 22 71 22 87 l0 30 -585 0 -584 0 243 725 243 725 -757 2 -758 3 114 330 c63 181 114 333 114 337 0 15 -535 9 -648 -8 -223 -33 -399 -111 -523 -234 -115 -114 -159 -220 -159 -388 0 -151 46 -258 155 -361 52 -49 161 -111 197 -111 9 0 20 -4 23 -10 3 -5 -76 -235 -176 -510 l-182 -500 -1106 0 c-712 0 -1129 4 -1170 10 -81 14 -152 50 -188 97 -26 33 -28 43 -28 122 0 83 4 97 119 433 l118 348 294 0 294 0 -150 -300 -150 -300 461 0 461 0 47 34 c57 42 139 128 169 177 61 101 86 251 58 358 -24 93 -62 155 -137 225 -132 122 -356 204 -641 235 -126 14 -690 14 -816 0 -379 -41 -695 -175 -915 -388 -191 -184 -279 -395 -280 -666 -1 -142 14 -221 58 -320 14 -32 24 -60 22 -62 -2 -2 -258 -2 -569 -1 l-565 3 184 530 c102 292 191 562 200 600 40 185 -22 329 -159 370 -137 40 -437 -8 -620 -101 -115 -58 -200 -123 -638 -486 -250 -208 -458 -378 -461 -378 -4 0 171 534 387 1188 217 653 394 1188 394 1190 0 1 -223 2 -494 2 l-495 0 -483 -1457z m-6258 -460 c0 -5 -74 -231 -164 -503 l-164 -495 -89 3 c-213 8 -346 60 -394 154 -42 82 -25 142 232 826 l9 22 285 0 c157 0 285 -3 285 -7z"Tb4b4b4/Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72gTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72svgTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72aTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"nav-subtitle"Tb4b4b4>// FLASHERTb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72a Te6edf3v-ifTff7b72=Ta5d6ff"brand.statsUrl" Te6edf3:hrefTff7b72=Ta5d6ff"brand.statsUrl" Te6edf3classTff7b72=Ta5d6ff"nav-git-link"Tb4b4b4>{{ t('nav.stats') }}Tb4b4b4<Tb4b4b4/Tff7b72aTb4b4b4>
Tb4b4b4<Tff7b72a Te6edf3v-ifTff7b72=Ta5d6ff"brand.docsUrl" Te6edf3:hrefTff7b72=Ta5d6ff"brand.docsUrl" Te6edf3targetTff7b72=Ta5d6ff"_blank" Te6edf3relTff7b72=Ta5d6ff"noopener" Te6edf3classTff7b72=Ta5d6ff"nav-git-link"Tb4b4b4>DocsTb4b4b4<Tb4b4b4/Tff7b72aTb4b4b4>
Tb4b4b4<Tff7b72a Te6edf3v-ifTff7b72=Ta5d6ff"brand.gitUrl" Te6edf3:hrefTff7b72=Ta5d6ff"brand.gitUrl" Te6edf3targetTff7b72=Ta5d6ff"_blank" Te6edf3relTff7b72=Ta5d6ff"noopener" Te6edf3classTff7b72=Ta5d6ff"nav-git-link"Tb4b4b4>GitTb4b4b4<Tb4b4b4/Tff7b72aTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"theme-toggle" @Te6edf3clickTff7b72=Ta5d6ff"toggleTheme" Te6edf3:titleTff7b72=Ta5d6ff"theme === 'dark' ? 'Switch to light theme' : 'Switch to dark theme'"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"theme === 'dark'"Tb4b4b4>Te6edf3&#9728;Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-elseTb4b4b4>Te6edf3&#9790;Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"lang-toggle"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"lang-btn" Te6edf3:classTff7b72=Ta5d6ff"{ active: lang === brand.altLang }" @Te6edf3clickTff7b72=Ta5d6ff"setLang(brand.altLang)"Tb4b4b4>{{ brand.altLang.toUpperCase() }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"lang-sep"Tb4b4b4>|Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"lang-btn" Te6edf3:classTff7b72=Ta5d6ff"{ active: lang === 'en' }" @Te6edf3clickTff7b72=Ta5d6ff"setLang('en')"Tb4b4b4>ENTb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72navTb4b4b4>

Tb4b4b4<Tff7b72mainTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"container"Tb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"flasher-header"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"header-prefix"Tb4b4b4>{{ t('header.prefix') }}Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72h1 Te6edf3classTff7b72=Ta5d6ff"header-title"Tb4b4b4>{{ isSecureContext ? '>_ RNode Flasher' : '>_ RNode WebSocket Configurator' }}Tb4b4b4<Tb4b4b4/Tff7b72h1Tb4b4b4>
Tb4b4b4<Tff7b72p Te6edf3classTff7b72=Ta5d6ff"header-desc" Te6edf3v-htmlTff7b72=Ta5d6ff"isSecureContext ? t('header.desc') : t('header.desc_ws')"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72pTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"isSecureContext && !hasSerial" Te6edf3classTff7b72=Ta5d6ff"browser-warning"Tb4b4b4>
{{ t('warning.serial') }}
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"flasher-grid"Tb4b4b4>

T8b949e<!-- ── CONFIG PANEL ──────────────────────────────────────── -->
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"panel config-panel"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"panel-title"Tb4b4b4>{{ t('panel.device') }}Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"config-body"Tb4b4b4>

Tb4b4b4<Tff7b72template Te6edf3v-ifTff7b72=Ta5d6ff"isSecureContext"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"port-row"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"connect-split"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm connect-btn" Te6edf3:classTff7b72=Ta5d6ff"{ 'is-connected': connectedPort }"
@Te6edf3clickTff7b72=Ta5d6ff"connectedPort ? disconnectDevice() : detectDevice()" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking || connectedNetworkUrl"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"connect-label"Tb4b4b4>{{ connectedPort ? t('btn.connected') : t('btn.connect') }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"disconnect-label"Tb4b4b4>{{ t('btn.disconnect') }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72select Te6edf3classTff7b72=Ta5d6ff"transport-select" Te6edf3v-modelTff7b72=Ta5d6ff"transportChoice" @Te6edf3changeTff7b72=Ta5d6ff"onTransportChange"
Te6edf3:disabledTff7b72=Ta5d6ff"isWorking || connectedPort" Te6edf3:titleTff7b72=Ta5d6ff"t('transport.hint')"Tb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3valueTff7b72=Ta5d6ff"usb"Tb4b4b4>{{ t('transport.usb') }}Tb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3valueTff7b72=Ta5d6ff"ws" Te6edf3:disabledTff7b72=Ta5d6ff"!brand.wsUrl"Tb4b4b4>{{ t('transport.ws') }}Tb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72selectTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"connectedDevice" Te6edf3classTff7b72=Ta5d6ff"port-badge"Tb4b4b4>{{ connectedDevice }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"connectedFwVer" Te6edf3classTff7b72=Ta5d6ff"fw-badge"Tb4b4b4>{{ connectedFwVer }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"connectedPlatformLabel" Te6edf3classTff7b72=Ta5d6ff"platform-badge"Tb4b4b4>{{ connectedPlatformLabel }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"!connectedFwVer && detectedChip" Te6edf3classTff7b72=Ta5d6ff"port-badge"Tb4b4b4>{{ detectedChip }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"field-group"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"field-label"Tb4b4b4>
{{ t('device.label') }}
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"detectedChip || detectedPlatformFamily" Te6edf3classTff7b72=Ta5d6ff"chip-badge"Tb4b4b4>{{ t('device.filtered') }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"select-wrapper"Tb4b4b4>
Tb4b4b4<Tff7b72select Te6edf3v-modelTff7b72=Ta5d6ff"selectedDevice" @Te6edf3changeTff7b72=Ta5d6ff"onDeviceChange" Te6edf3classTff7b72=Ta5d6ff"field-select" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"null" Te6edf3disabledTb4b4b4>{{ t('device.placeholder') }}Tb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72optgroup Te6edf3v-forTff7b72=Ta5d6ff"grp in filteredDeviceGroups" Te6edf3:keyTff7b72=Ta5d6ff"grp.label" Te6edf3:labelTff7b72=Ta5d6ff"grp.label"Tb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3v-forTff7b72=Ta5d6ff"dev in grp.devices" Te6edf3:keyTff7b72=Ta5d6ff"dev.name" Te6edf3:valueTff7b72=Ta5d6ff"dev"Tb4b4b4>{{ dev.name }}Tb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72optgroupTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72selectTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"field-group" Te6edf3v-ifTff7b72=Ta5d6ff"selectedDevice"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"field-label"Tb4b4b4>{{ t('variant.label') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"select-wrapper"Tb4b4b4>
Tb4b4b4<Tff7b72select Te6edf3v-modelTff7b72=Ta5d6ff"selectedVariant" Te6edf3classTff7b72=Ta5d6ff"field-select" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"null" Te6edf3disabledTb4b4b4>{{ t('variant.placeholder') }}Tb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3v-forTff7b72=Ta5d6ff"v in visibleVariants" Te6edf3:keyTff7b72=Ta5d6ff"v.name" Te6edf3:valueTff7b72=Ta5d6ff"v"Tb4b4b4>{{ v.name }}Tb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72selectTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"firmware-hint" Te6edf3v-ifTff7b72=Ta5d6ff"selectedVariant"Tb4b4b4>
Tb4b4b4<Tff7b72template Te6edf3v-ifTff7b72=Ta5d6ff"selectedFirmwareInfo"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"hint-key"Tb4b4b4>version: Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"hint-val"Tb4b4b4>{{ selectedFirmwareInfo.version }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72brTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72templateTb4b4b4>
Tb4b4b4<Tff7b72template Te6edf3v-ifTff7b72=Ta5d6ff"selectedFirmwareInfo && selectedFirmwareInfo.date"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"hint-key"Tb4b4b4>published: Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"hint-val"Tb4b4b4>{{ selectedFirmwareInfo.date }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72brTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72templateTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"hint-key"Tb4b4b4>zip: Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>Tb4b4b4<Tff7b72a Te6edf3classTff7b72=Ta5d6ff"hint-val" Te6edf3:hrefTff7b72=Ta5d6ff"selectedVariant.firmware_zip" Te6edf3:downloadTff7b72=Ta5d6ff"selectedVariant.firmware_zip.split('/').pop()"Tb4b4b4>{{ selectedVariant.firmware_zip.split('/').pop() }}Tb4b4b4<Tb4b4b4/Tff7b72aTb4b4b4>
Tb4b4b4<Tff7b72template Te6edf3v-ifTff7b72=Ta5d6ff"uf2Exists"Tb4b4b4>
Tb4b4b4<Tff7b72brTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"hint-key"Tb4b4b4>uf2: Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>Tb4b4b4<Tff7b72a Te6edf3classTff7b72=Ta5d6ff"hint-val" Te6edf3:hrefTff7b72=Ta5d6ff"uf2Url" Te6edf3:downloadTff7b72=Ta5d6ff"uf2Url.split('/').pop()"Tb4b4b4>{{ uf2Url.split('/').pop() }}Tb4b4b4<Tb4b4b4/Tff7b72aTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72templateTb4b4b4>
Tb4b4b4<Tff7b72brTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"hint-key"Tb4b4b4>flash: Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"hint-val" Te6edf3v-ifTff7b72=Ta5d6ff"selectedVariant.platform === 'nrf52'"Tb4b4b4>nRF52 DFUTb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"hint-val" Te6edf3v-elseTb4b4b4>{{ selectedVariant.flash_config.flash_size }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"selectedVariant.needs_provisioning"Tb4b4b4>
Te6edf3&nbsp;Β·Te6edf3&nbsp;Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"hint-key"Tb4b4b4>{{ t('hint.provision') }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"hint-val"Tb4b4b4>{{ t('hint.yes') }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-flash" Te6edf3:classTff7b72=Ta5d6ff"{ 'btn-flash-update': firmwareUpdateAvailable }" @Te6edf3clickTff7b72=Ta5d6ff"flashAll" Te6edf3:disabledTff7b72=Ta5d6ff"!canFlash"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"!isWorking" Te6edf3classTff7b72=Ta5d6ff"btn-flash-inner" Te6edf3v-htmlTff7b72=Ta5d6ff"firmwareUpdateAvailable ? t('btn.update') : t('btn.flash')"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-else Te6edf3classTff7b72=Ta5d6ff"btn-flash-inner"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"spinner"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
{{ currentStep }}
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72templateTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"port-row" Te6edf3v-ifTff7b72=Ta5d6ff"!isSecureContext"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"connect-split"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm connect-btn" Te6edf3:classTff7b72=Ta5d6ff"{ 'is-connected': connectedNetworkUrl }"
@Te6edf3clickTff7b72=Ta5d6ff"connectedNetworkUrl ? disconnectNetworkDevice() : detectDeviceOverNetwork()" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking || (!connectedNetworkUrl && !networkHost.trim())"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"connect-label"Tb4b4b4>{{ connectedNetworkUrl ? t('btn.connected') : t('btn.connect') }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"disconnect-label"Tb4b4b4>{{ t('btn.disconnect') }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72select Te6edf3classTff7b72=Ta5d6ff"transport-select" Te6edf3v-modelTff7b72=Ta5d6ff"transportChoice" @Te6edf3changeTff7b72=Ta5d6ff"onTransportChange"
Te6edf3:disabledTff7b72=Ta5d6ff"isWorking || connectedNetworkUrl" Te6edf3:titleTff7b72=Ta5d6ff"t('transport.hint')"Tb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3valueTff7b72=Ta5d6ff"usb" Te6edf3:disabledTff7b72=Ta5d6ff"!brand.usbUrl"Tb4b4b4>{{ t('transport.usb') }}Tb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3valueTff7b72=Ta5d6ff"ws"Tb4b4b4>{{ t('transport.ws') }}Tb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72selectTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3v-ifTff7b72=Ta5d6ff"!connectedNetworkUrl" Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"text" Te6edf3v-modelTff7b72=Ta5d6ff"networkHost" Te6edf3placeholderTff7b72=Ta5d6ff"192.168.0.32"
Te6edf3:disabledTff7b72=Ta5d6ff"isWorking" Te6edf3styleTff7b72=Ta5d6ff"max-width:8rem;"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"connectedDevice" Te6edf3classTff7b72=Ta5d6ff"port-badge"Tb4b4b4>{{ connectedDevice }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"connectedFwVer" Te6edf3classTff7b72=Ta5d6ff"fw-badge"Tb4b4b4>{{ connectedFwVer }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"connectedPlatformLabel" Te6edf3classTff7b72=Ta5d6ff"platform-badge"Tb4b4b4>{{ connectedPlatformLabel }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"progress-wrap" Te6edf3v-ifTff7b72=Ta5d6ff"flashProgress > 0"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"progress-bar"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"progress-fill" Te6edf3:styleTff7b72=Ta5d6ff"{ width: flashProgress + '%' }"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"progress-text"Tb4b4b4>{{ flashProgress }}%Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>


Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"statusMsg" Te6edf3classTff7b72=Ta5d6ff"status-badge" Te6edf3:classTff7b72=Ta5d6ff"detectedStatusClass"Tb4b4b4>{{ detectedStatusText }}Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"panel-sep"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"advanced-toggle" @Te6edf3clickTff7b72=Ta5d6ff"showAdvanced = !showAdvanced"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"adv-arrow" Te6edf3:classTff7b72=Ta5d6ff"{ open: showAdvanced }"Tb4b4b4>β–ΆTb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
{{ t('adv.toggle') }}
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"showAdvanced" Te6edf3classTff7b72=Ta5d6ff"advanced-body"Tb4b4b4>
T8b949e<!-- Detect/Reboot/Dump/Screen all go through withRNode(), which
works over either transport - so these stay available on
both origins. Flash/Erase/DFU/Provision/Hash/other-firmware
filter need real USB bootloader access with no network
equivalent, so those stay gated to the secure (USB) origin. -->
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"detectRNode" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('adv.detect') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"rebootRNode" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('adv.reboot') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"dumpEeprom" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('adv.dump') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"readScreen" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking || autoRefresh"Tb4b4b4>{{ t('adv.screen') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72template Te6edf3v-ifTff7b72=Ta5d6ff"isSecureContext"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3v-ifTff7b72=Ta5d6ff"nrf52Relevant" Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"enterNrf52Dfu" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking" Te6edf3:titleTff7b72=Ta5d6ff"t('adv.dfu.hint')"Tb4b4b4>{{ t('adv.dfu') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm danger" @Te6edf3clickTff7b72=Ta5d6ff"eraseFlash" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('adv.erase') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm danger" @Te6edf3clickTff7b72=Ta5d6ff"wipeEeprom" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('adv.wipe') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"manualProvision" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking || !selectedVariant || !selectedVariant.needs_provisioning" Te6edf3:titleTff7b72=Ta5d6ff"!selectedVariant || !selectedVariant.needs_provisioning ? 'Select a provisionable variant first' : ''"Tb4b4b4>{{ t('adv.provision') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"manualSetHash" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('adv.hash') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"adv-checkbox"Tb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3typeTff7b72=Ta5d6ff"checkbox" Te6edf3v-modelTff7b72=Ta5d6ff"showOtherFirmwares"Tb4b4b4>
{{ t('adv.other_fw') }}
Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72templateTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"screenImage" Te6edf3classTff7b72=Ta5d6ff"screen-dump"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"screen-label"Tb4b4b4>
{{ t('screen.label') }}
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"screen-actions"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-icon" Te6edf3:classTff7b72=Ta5d6ff"{ 'auto-active': autoRefresh }" @Te6edf3clickTff7b72=Ta5d6ff"toggleAutoRefresh" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking && !autoRefresh"Tb4b4b4>{{ autoRefresh ? t('btn.stop_auto') : t('btn.auto') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-icon" @Te6edf3clickTff7b72=Ta5d6ff"autoRefresh = false; screenImage = null"Tb4b4b4>{{ t('btn.close') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72img Te6edf3:srcTff7b72=Ta5d6ff"screenImage" Te6edf3classTff7b72=Ta5d6ff"screen-img" Te6edf3altTff7b72=Ta5d6ff"RNode screen"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

T8b949e<!-- ── SERIAL MONITOR ───────────────────────────────────── -->
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"panel monitor-panel"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"panel-title"Tb4b4b4>
{{ t('monitor.title') }}
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-icon" @Te6edf3clickTff7b72=Ta5d6ff"clearLog"Tb4b4b4>{{ t('btn.clear') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"monitor-body" Te6edf3refTff7b72=Ta5d6ff"monitorEl"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"log.length === 0" Te6edf3classTff7b72=Ta5d6ff"monitor-empty"Tb4b4b4>{{ t('monitor.empty') }}Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-forTff7b72=Ta5d6ff"(entry, i) in log" Te6edf3:keyTff7b72=Ta5d6ff"i" Te6edf3classTff7b72=Ta5d6ff"log-line" Te6edf3:classTff7b72=Ta5d6ff"entry.type"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"log-pfx"Tb4b4b4>{{ entry.pfx }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"log-txt"Tb4b4b4>{{ entry.txt }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"isWorking" Te6edf3classTff7b72=Ta5d6ff"log-cursor"Tb4b4b4>Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"cursor-blink"Tb4b4b4>β–ŒTb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

T8b949e<!-- ── NODE CONFIGURATION ─────────────────────────────── -->
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"panel node-cfg-panel" Te6edf3:classTff7b72=Ta5d6ff"{ 'panel-inactive': !hasLiveConnection }"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"panel-title"Tb4b4b4>{{ t('cfg.title') }}Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-main"Tb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"tab-bar"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"tab" Te6edf3:classTff7b72=Ta5d6ff"{ active: cfgTab==='radio' }" @Te6edf3clickTff7b72=Ta5d6ff"selectTab('radio')"Tb4b4b4>{{ t('tab.radio') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"tab" Te6edf3:classTff7b72=Ta5d6ff"{ active: cfgTab==='display' }" @Te6edf3clickTff7b72=Ta5d6ff"selectTab('display')"Tb4b4b4>{{ t('tab.display') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3v-ifTff7b72=Ta5d6ff"!wifiHidden" Te6edf3classTff7b72=Ta5d6ff"tab" Te6edf3:classTff7b72=Ta5d6ff"{ active: cfgTab==='wifi' }" @Te6edf3clickTff7b72=Ta5d6ff"selectTab('wifi')"Tb4b4b4>{{ t('tab.wifi') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3v-ifTff7b72=Ta5d6ff"!ethernetHidden" Te6edf3classTff7b72=Ta5d6ff"tab" Te6edf3:classTff7b72=Ta5d6ff"{ active: cfgTab==='ethernet', disabled: connectedDevice && !ethernetSupported }" Te6edf3:titleTff7b72=Ta5d6ff"connectedDevice && !ethernetSupported ? t('tab.ethernet.unsupported') : ''" @Te6edf3clickTff7b72=Ta5d6ff"selectTab('ethernet')"Tb4b4b4>{{ t('tab.ethernet') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"tab" Te6edf3:classTff7b72=Ta5d6ff"{ active: cfgTab==='bluetooth' }" @Te6edf3clickTff7b72=Ta5d6ff"selectTab('bluetooth')"Tb4b4b4>{{ t('tab.bluetooth') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3v-ifTff7b72=Ta5d6ff"miscSupported" Te6edf3classTff7b72=Ta5d6ff"tab" Te6edf3:classTff7b72=Ta5d6ff"{ active: cfgTab==='misc' }" @Te6edf3clickTff7b72=Ta5d6ff"selectTab('misc')"Tb4b4b4>{{ t('tab.misc') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"tab" Te6edf3:classTff7b72=Ta5d6ff"{ active: cfgTab==='info' }" @Te6edf3clickTff7b72=Ta5d6ff"selectTab('info')" Te6edf3styleTff7b72=Ta5d6ff"margin-left:auto"Tb4b4b4>{{ t('tab.info') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-panes-wrap"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"!hasLiveConnection && cfgTab !== 'info'" Te6edf3classTff7b72=Ta5d6ff"cfg-inactive-cross"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"!hasLiveConnection && cfgTab !== 'info'" Te6edf3classTff7b72=Ta5d6ff"panel-inactive-overlay"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"panel-inactive-label"Tb4b4b4>{{ t('cfg.not_connected') }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-panes" Te6edf3:classTff7b72=Ta5d6ff"{ 'tab-panes-disabled': !hasLiveConnection && cfgTab !== 'info' }"Tb4b4b4>

T8b949e<!-- Radio -->
Tb4b4b4<Tff7b72div Te6edf3v-showTff7b72=Ta5d6ff"cfgTab==='radio'" Te6edf3classTff7b72=Ta5d6ff"tab-pane"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-notice"Tb4b4b4>{{ t('radio.notice') }}Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-actions" Te6edf3styleTff7b72=Ta5d6ff"margin-bottom:0.4rem;"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: tncEnabled === true }"
@Te6edf3clickTff7b72=Ta5d6ff"enableTnc" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking || tncEnabled === true"Tb4b4b4>{{ t('btn.enable_tnc') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm orange" Te6edf3:classTff7b72=Ta5d6ff"{ active: tncEnabled === false }"
@Te6edf3clickTff7b72=Ta5d6ff"disableTnc" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking || tncEnabled === false"Tb4b4b4>{{ t('btn.disable_tnc') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"tncEnabled === true" Te6edf3classTff7b72=Ta5d6ff"tnc-badge tnc-on"Tb4b4b4>{{ t('tnc.on') }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"tncEnabled === false" Te6edf3classTff7b72=Ta5d6ff"tnc-badge tnc-off"Tb4b4b4>{{ t('tnc.off') }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-grid"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('cfg.freq') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"number" Te6edf3stepTff7b72=Ta5d6ff"0.001" Te6edf3v-modelTff7b72=Ta5d6ff"radioFreqMhz" Te6edf3placeholderTff7b72=Ta5d6ff"868.000" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('cfg.bw') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"select-wrapper"Tb4b4b4>
Tb4b4b4<Tff7b72select Te6edf3classTff7b72=Ta5d6ff"field-select" Te6edf3v-model.Te6edf3numberTff7b72=Ta5d6ff"radioBwHz" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"7800"Tb4b4b4>7.8 kHzTb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"10400"Tb4b4b4>10.4 kHzTb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"15600"Tb4b4b4>15.6 kHzTb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"20800"Tb4b4b4>20.8 kHzTb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"31250"Tb4b4b4>31.25 kHzTb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"41700"Tb4b4b4>41.7 kHzTb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"62500"Tb4b4b4>62.5 kHzTb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"125000"Tb4b4b4>125 kHzTb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"250000"Tb4b4b4>250 kHzTb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3:valueTff7b72=Ta5d6ff"500000"Tb4b4b4>500 kHzTb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72selectTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('cfg.sf') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"select-wrapper"Tb4b4b4>
Tb4b4b4<Tff7b72select Te6edf3classTff7b72=Ta5d6ff"field-select" Te6edf3v-model.Te6edf3numberTff7b72=Ta5d6ff"radioSf" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3v-forTff7b72=Ta5d6ff"sf in [7,8,9,10,11,12]" Te6edf3:valueTff7b72=Ta5d6ff"sf"Tb4b4b4>SF{{ sf }}Tb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72selectTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('cfg.cr') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"select-wrapper"Tb4b4b4>
Tb4b4b4<Tff7b72select Te6edf3classTff7b72=Ta5d6ff"field-select" Te6edf3v-model.Te6edf3numberTff7b72=Ta5d6ff"radioCr" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tff7b72option Te6edf3v-forTff7b72=Ta5d6ff"cr in [5,6,7,8]" Te6edf3:valueTff7b72=Ta5d6ff"cr"Tb4b4b4>4/{{ cr }}Tb4b4b4<Tb4b4b4/Tff7b72optionTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72selectTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field cfg-field-wide"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('cfg.txpower') }} β€” {{ radioTxPower }} dBmTb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-range" Te6edf3typeTff7b72=Ta5d6ff"range" Te6edf3minTff7b72=Ta5d6ff"0" Te6edf3maxTff7b72=Ta5d6ff"30" Te6edf3v-model.Te6edf3numberTff7b72=Ta5d6ff"radioTxPower" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-actions"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"applyRadio" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking || !(parseFloat(radioFreqMhz) > 0)"Tb4b4b4>{{ t('btn.apply') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

T8b949e<!-- Display -->
Tb4b4b4<Tff7b72div Te6edf3v-showTff7b72=Ta5d6ff"cfgTab==='display'" Te6edf3classTff7b72=Ta5d6ff"tab-pane"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('cfg.rotation') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-row"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: dispRotation===0 }" @Te6edf3clickTff7b72=Ta5d6ff"dispRotation=0" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>0Β°Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: dispRotation===1 }" @Te6edf3clickTff7b72=Ta5d6ff"dispRotation=1" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>90Β°Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: dispRotation===2 }" @Te6edf3clickTff7b72=Ta5d6ff"dispRotation=2" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>180Β°Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: dispRotation===3 }" @Te6edf3clickTff7b72=Ta5d6ff"dispRotation=3" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>270Β°Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field" Te6edf3v-ifTff7b72=Ta5d6ff"oledDisplay"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('cfg.intensity') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-row"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm orange" Te6edf3:classTff7b72=Ta5d6ff"{ active: dispIntensity===0 }" @Te6edf3clickTff7b72=Ta5d6ff"dispIntensity=0" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('cfg.intensity.off') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: dispIntensity===1 }" @Te6edf3clickTff7b72=Ta5d6ff"dispIntensity=1" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('cfg.intensity.dim') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: dispIntensity===255 }" @Te6edf3clickTff7b72=Ta5d6ff"dispIntensity=255" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('cfg.intensity.bright') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field" Te6edf3v-elseTb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('cfg.intensity') }} β€” {{ dispIntensity }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-range" Te6edf3typeTff7b72=Ta5d6ff"range" Te6edf3minTff7b72=Ta5d6ff"0" Te6edf3maxTff7b72=Ta5d6ff"255" Te6edf3v-model.Te6edf3numberTff7b72=Ta5d6ff"dispIntensity" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('cfg.timeout') }} β€” {{ dispTimeout === 0 ? t('cfg.timeout.always') : dispTimeout }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-range" Te6edf3typeTff7b72=Ta5d6ff"range" Te6edf3minTff7b72=Ta5d6ff"0" Te6edf3maxTff7b72=Ta5d6ff"255" Te6edf3v-model.Te6edf3numberTff7b72=Ta5d6ff"dispTimeout" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-actions"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"applyDisplay" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.apply') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: isReconditioning }" @Te6edf3clickTff7b72=Ta5d6ff"doReconditionDisplay" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ isReconditioning ? t('btn.stop_recondition') : t('btn.recondition') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

T8b949e<!-- WiFi -->
Tb4b4b4<Tff7b72div Te6edf3v-showTff7b72=Ta5d6ff"cfgTab==='wifi'" Te6edf3classTff7b72=Ta5d6ff"tab-pane"Tb4b4b4>
T8b949e<!-- Row 1: Mode + Channel -->
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-row" Te6edf3styleTff7b72=Ta5d6ff"align-items:flex-end; gap:1rem;"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('wifi.mode') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-row"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm orange" Te6edf3:classTff7b72=Ta5d6ff"{ active: wifiMode===0 }" @Te6edf3clickTff7b72=Ta5d6ff"wifiMode=0" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.off') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: wifiMode===1 }" @Te6edf3clickTff7b72=Ta5d6ff"wifiMode=1" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.station') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: wifiMode===2 }" @Te6edf3clickTff7b72=Ta5d6ff"wifiMode=2" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.ap') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('wifi.channel') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"number" Te6edf3minTff7b72=Ta5d6ff"1" Te6edf3maxTff7b72=Ta5d6ff"13" Te6edf3v-model.Te6edf3numberTff7b72=Ta5d6ff"wifiChannel" Te6edf3styleTff7b72=Ta5d6ff"width:4rem;" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
T8b949e<!-- Rows 2–3: paired fields -->
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-grid cfg-grid-2col" Te6edf3styleTff7b72=Ta5d6ff"margin-top:0.5rem;"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('wifi.ssid') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"text" Te6edf3v-modelTff7b72=Ta5d6ff"wifiSsid" Te6edf3:placeholderTff7b72=Ta5d6ff"t('wifi.ssid.ph')" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('wifi.psk') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"password" Te6edf3v-modelTff7b72=Ta5d6ff"wifiPsk" Te6edf3:placeholderTff7b72=Ta5d6ff"t('wifi.psk.ph')" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('wifi.ip') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"text" Te6edf3v-modelTff7b72=Ta5d6ff"wifiIp" Te6edf3placeholderTff7b72=Ta5d6ff"192.168.0.32" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('wifi.nm') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"text" Te6edf3v-modelTff7b72=Ta5d6ff"wifiNm" Te6edf3placeholderTff7b72=Ta5d6ff"255.255.255.0" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('wifi.gw') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"text" Te6edf3v-modelTff7b72=Ta5d6ff"wifiGw" Te6edf3placeholderTff7b72=Ta5d6ff"192.168.0.1" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('wifi.dns') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"text" Te6edf3v-modelTff7b72=Ta5d6ff"wifiDns" Te6edf3placeholderTff7b72=Ta5d6ff"192.168.0.1" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-actions"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"applyWifi" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.apply') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm orange" @Te6edf3clickTff7b72=Ta5d6ff"clearWifi" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.clear_cfg') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

T8b949e<!-- Ethernet -->
Tb4b4b4<Tff7b72div Te6edf3v-showTff7b72=Ta5d6ff"cfgTab==='ethernet'" Te6edf3classTff7b72=Ta5d6ff"tab-pane"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-notice"Tb4b4b4>{{ t('eth.speed_notice') }}Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('eth.speed') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-row eth-speed-row"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm btn-xs orange" Te6edf3:classTff7b72=Ta5d6ff"{ active: ethSpeed===5 }" @Te6edf3clickTff7b72=Ta5d6ff"ethSpeed=5" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.eth_off') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm btn-xs" Te6edf3:classTff7b72=Ta5d6ff"{ active: ethSpeed===0 }" @Te6edf3clickTff7b72=Ta5d6ff"ethSpeed=0" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.eth_auto') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm btn-xs" Te6edf3:classTff7b72=Ta5d6ff"{ active: ethSpeed===1 }" @Te6edf3clickTff7b72=Ta5d6ff"ethSpeed=1" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>100/FULLTb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm btn-xs" Te6edf3:classTff7b72=Ta5d6ff"{ active: ethSpeed===2 }" @Te6edf3clickTff7b72=Ta5d6ff"ethSpeed=2" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>100/HALFTb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm btn-xs" Te6edf3:classTff7b72=Ta5d6ff"{ active: ethSpeed===3 }" @Te6edf3clickTff7b72=Ta5d6ff"ethSpeed=3" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>10/FULLTb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm btn-xs" Te6edf3:classTff7b72=Ta5d6ff"{ active: ethSpeed===4 }" @Te6edf3clickTff7b72=Ta5d6ff"ethSpeed=4" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>10/HALFTb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-grid cfg-grid-2col" Te6edf3styleTff7b72=Ta5d6ff"margin-top:0.5rem;"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('eth.ip') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"text" Te6edf3v-modelTff7b72=Ta5d6ff"ethIp" Te6edf3placeholderTff7b72=Ta5d6ff"192.168.0.32" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('eth.nm') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"text" Te6edf3v-modelTff7b72=Ta5d6ff"ethNm" Te6edf3placeholderTff7b72=Ta5d6ff"255.255.255.0" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('eth.gw') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"text" Te6edf3v-modelTff7b72=Ta5d6ff"ethGw" Te6edf3placeholderTff7b72=Ta5d6ff"192.168.0.1" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('eth.dns') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-input" Te6edf3typeTff7b72=Ta5d6ff"text" Te6edf3v-modelTff7b72=Ta5d6ff"ethDns" Te6edf3placeholderTff7b72=Ta5d6ff"192.168.0.1" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-actions"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"applyEthernet" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.apply') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm orange" @Te6edf3clickTff7b72=Ta5d6ff"clearEthernet" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.clear_cfg') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

T8b949e<!-- Bluetooth -->
Tb4b4b4<Tff7b72div Te6edf3v-showTff7b72=Ta5d6ff"cfgTab==='bluetooth'" Te6edf3classTff7b72=Ta5d6ff"tab-pane"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('bt.label') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-row"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: btEnabled }" @Te6edf3clickTff7b72=Ta5d6ff"setBluetooth(true)" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.bt_enable') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm orange" Te6edf3:classTff7b72=Ta5d6ff"{ active: !btEnabled }" @Te6edf3clickTff7b72=Ta5d6ff"setBluetooth(false)" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.bt_disable') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm btn-blue" @Te6edf3clickTff7b72=Ta5d6ff"startPairing" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking || !btEnabled"Tb4b4b4>
{{ btPairing ? t('btn.bt_pairing') : t('btn.bt_pair') }}
Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"btPairing || btPin" Te6edf3classTff7b72=Ta5d6ff"bt-pin-display"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"bt-pin-label"Tb4b4b4>{{ btPin ? t('bt.pin.label') : t('bt.pin.connect') }}Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"bt-pin-code"Tb4b4b4>{{ btPin || 'Β·Β·Β·Β·Β·Β·' }}Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

T8b949e<!-- Misc (homebrew-only extras) -->
Tb4b4b4<Tff7b72div Te6edf3v-showTff7b72=Ta5d6ff"cfgTab==='misc'" Te6edf3classTff7b72=Ta5d6ff"tab-pane"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('misc.sound') }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-row"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" Te6edf3:classTff7b72=Ta5d6ff"{ active: sndEnabled === true }" @Te6edf3clickTff7b72=Ta5d6ff"setSound(true)" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.snd_enable') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm orange" Te6edf3:classTff7b72=Ta5d6ff"{ active: sndEnabled === false }" @Te6edf3clickTff7b72=Ta5d6ff"setSound(false)" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.snd_disable') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('misc.vsense') }} β€” {{ vsenseDivider.toFixed(1) }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72input Te6edf3classTff7b72=Ta5d6ff"cfg-range" Te6edf3typeTff7b72=Ta5d6ff"range" Te6edf3minTff7b72=Ta5d6ff"1" Te6edf3maxTff7b72=Ta5d6ff"25" Te6edf3stepTff7b72=Ta5d6ff"0.1" Te6edf3v-model.Te6edf3numberTff7b72=Ta5d6ff"vsenseDivider" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-actions"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"applyMisc" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.apply') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-field"Tb4b4b4>
Tb4b4b4<Tff7b72label Te6edf3classTff7b72=Ta5d6ff"cfg-label"Tb4b4b4>{{ t('misc.rtc') }} β€” {{ rtcTimeDisplay }}Tb4b4b4<Tb4b4b4/Tff7b72labelTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"cfg-row"Tb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"syncRtcFromBrowser" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.rtc_sync_browser') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm" @Te6edf3clickTff7b72=Ta5d6ff"syncRtcFromNtp" Te6edf3:disabledTff7b72=Ta5d6ff"isWorking"Tb4b4b4>{{ t('btn.rtc_sync_ntp') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

T8b949e<!-- H/W Info -->
Tb4b4b4<Tff7b72div Te6edf3v-showTff7b72=Ta5d6ff"cfgTab === 'info'" Te6edf3classTff7b72=Ta5d6ff"tab-pane hw-info-pane"Tb4b4b4>
Tb4b4b4<Tff7b72template Te6edf3v-ifTff7b72=Ta5d6ff"hwInfo"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"hw-info-layout"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"hw-device-visual"Tb4b4b4>
Tb4b4b4<Tff7b72img Te6edf3v-ifTff7b72=Ta5d6ff"hwInfo.image" Te6edf3:srcTff7b72=Ta5d6ff"hwInfo.image" Te6edf3:altTff7b72=Ta5d6ff"selectedDevice.name" Te6edf3classTff7b72=Ta5d6ff"hw-device-img"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-else Te6edf3classTff7b72=Ta5d6ff"hw-device-placeholder"Tb4b4b4>
Tb4b4b4<Tff7b72svg Te6edf3widthTff7b72=Ta5d6ff"40" Te6edf3heightTff7b72=Ta5d6ff"40" Te6edf3viewBoxTff7b72=Ta5d6ff"0 0 24 24" Te6edf3fillTff7b72=Ta5d6ff"none" Te6edf3strokeTff7b72=Ta5d6ff"currentColor" Te6edf3stroke-widthTff7b72=Ta5d6ff"1.2" Te6edf3stroke-linecapTff7b72=Ta5d6ff"round" Te6edf3stroke-linejoinTff7b72=Ta5d6ff"round"Tb4b4b4>
Tb4b4b4<Tff7b72rect Te6edf3xTff7b72=Ta5d6ff"6" Te6edf3yTff7b72=Ta5d6ff"6" Te6edf3widthTff7b72=Ta5d6ff"12" Te6edf3heightTff7b72=Ta5d6ff"12" Te6edf3rxTff7b72=Ta5d6ff"1.5"Tb4b4b4/Tb4b4b4>
Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"9" Te6edf3y1Tff7b72=Ta5d6ff"3" Te6edf3x2Tff7b72=Ta5d6ff"9" Te6edf3y2Tff7b72=Ta5d6ff"6"Tb4b4b4/Tb4b4b4>Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"12" Te6edf3y1Tff7b72=Ta5d6ff"3" Te6edf3x2Tff7b72=Ta5d6ff"12" Te6edf3y2Tff7b72=Ta5d6ff"6"Tb4b4b4/Tb4b4b4>Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"15" Te6edf3y1Tff7b72=Ta5d6ff"3" Te6edf3x2Tff7b72=Ta5d6ff"15" Te6edf3y2Tff7b72=Ta5d6ff"6"Tb4b4b4/Tb4b4b4>
Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"9" Te6edf3y1Tff7b72=Ta5d6ff"18" Te6edf3x2Tff7b72=Ta5d6ff"9" Te6edf3y2Tff7b72=Ta5d6ff"21"Tb4b4b4/Tb4b4b4>Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"12" Te6edf3y1Tff7b72=Ta5d6ff"18" Te6edf3x2Tff7b72=Ta5d6ff"12" Te6edf3y2Tff7b72=Ta5d6ff"21"Tb4b4b4/Tb4b4b4>Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"15" Te6edf3y1Tff7b72=Ta5d6ff"18" Te6edf3x2Tff7b72=Ta5d6ff"15" Te6edf3y2Tff7b72=Ta5d6ff"21"Tb4b4b4/Tb4b4b4>
Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"3" Te6edf3y1Tff7b72=Ta5d6ff"9" Te6edf3x2Tff7b72=Ta5d6ff"6" Te6edf3y2Tff7b72=Ta5d6ff"9"Tb4b4b4/Tb4b4b4>Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"3" Te6edf3y1Tff7b72=Ta5d6ff"12" Te6edf3x2Tff7b72=Ta5d6ff"6" Te6edf3y2Tff7b72=Ta5d6ff"12"Tb4b4b4/Tb4b4b4>Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"3" Te6edf3y1Tff7b72=Ta5d6ff"15" Te6edf3x2Tff7b72=Ta5d6ff"6" Te6edf3y2Tff7b72=Ta5d6ff"15"Tb4b4b4/Tb4b4b4>
Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"18" Te6edf3y1Tff7b72=Ta5d6ff"9" Te6edf3x2Tff7b72=Ta5d6ff"21" Te6edf3y2Tff7b72=Ta5d6ff"9"Tb4b4b4/Tb4b4b4>Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"18" Te6edf3y1Tff7b72=Ta5d6ff"12" Te6edf3x2Tff7b72=Ta5d6ff"21" Te6edf3y2Tff7b72=Ta5d6ff"12"Tb4b4b4/Tb4b4b4>Tb4b4b4<Tff7b72line Te6edf3x1Tff7b72=Ta5d6ff"18" Te6edf3y1Tff7b72=Ta5d6ff"15" Te6edf3x2Tff7b72=Ta5d6ff"21" Te6edf3y2Tff7b72=Ta5d6ff"15"Tb4b4b4/Tb4b4b4>
Tb4b4b4<Tff7b72circle Te6edf3cxTff7b72=Ta5d6ff"12" Te6edf3cyTff7b72=Ta5d6ff"12" Te6edf3rTff7b72=Ta5d6ff"1.5" Te6edf3fillTff7b72=Ta5d6ff"currentColor" Te6edf3strokeTff7b72=Ta5d6ff"none"Tb4b4b4/Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72svgTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"hw-info-body"Tb4b4b4>
Tb4b4b4<Tff7b72p Te6edf3classTff7b72=Ta5d6ff"hw-info-desc"Tb4b4b4>{{ lang === 'ru' ? hwInfo.desc.ru : hwInfo.desc.en }}Tb4b4b4<Tb4b4b4/Tff7b72pTb4b4b4>
Tb4b4b4<Tff7b72table Te6edf3classTff7b72=Ta5d6ff"hw-specs-table"Tb4b4b4>
Tb4b4b4<Tff7b72tr Te6edf3v-forTff7b72=Ta5d6ff"spec in hwInfo.specs" Te6edf3:keyTff7b72=Ta5d6ff"spec.key"Tb4b4b4>
Tb4b4b4<Tff7b72td Te6edf3classTff7b72=Ta5d6ff"hw-spec-key"Tb4b4b4>{{ spec.key }}Tb4b4b4<Tb4b4b4/Tff7b72tdTb4b4b4>
Tb4b4b4<Tff7b72td Te6edf3classTff7b72=Ta5d6ff"hw-spec-val"Tb4b4b4>{{ spec.val }}Tb4b4b4<Tb4b4b4/Tff7b72tdTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72trTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72tableTb4b4b4>
Tb4b4b4<Tff7b72a Te6edf3:hrefTff7b72=Ta5d6ff"hwInfo.url" Te6edf3targetTff7b72=Ta5d6ff"_blank" Te6edf3relTff7b72=Ta5d6ff"noopener" Te6edf3classTff7b72=Ta5d6ff"btn-sm btn-blue hw-info-link"Tb4b4b4>{{ t('hw.info.link') }} β†—Tb4b4b4<Tb4b4b4/Tff7b72aTb4b4b4>
Tb4b4b4<Tff7b72button Te6edf3classTff7b72=Ta5d6ff"btn-sm hw-info-link" Te6edf3:classTff7b72=Ta5d6ff"{ active: linkCopied }" @Te6edf3clickTff7b72=Ta5d6ff"copyFlasherLink"Tb4b4b4>{{ linkCopied ? t('hw.info.copy_link_done') : t('hw.info.copy_link') }}Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72templateTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-else Te6edf3classTff7b72=Ta5d6ff"hw-info-empty"Tb4b4b4>
{{ selectedDevice ? t('hw.info.no_data') : t('hw.info.select') }}
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4> T8b949e<!-- /cfg-panes -->
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4> T8b949e<!-- /cfg-panes-wrap -->
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4> T8b949e<!-- /cfg-main -->
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>


Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72mainTb4b4b4>

Tb4b4b4<Tff7b72footerTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"container footer-inner"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"logo-text" Te6edf3styleTff7b72=Ta5d6ff"color:var(--accent-dim);font-size:0.9rem;"Tb4b4b4>{{ brand.name }}Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"footer-copy" Te6edf3v-ifTff7b72=Ta5d6ff"brand.firmwareUrl || brand.sourceUrl"Tb4b4b4>
Tb4b4b4<Tff7b72a Te6edf3v-ifTff7b72=Ta5d6ff"brand.firmwareUrl" Te6edf3:hrefTff7b72=Ta5d6ff"brand.firmwareUrl" Te6edf3targetTff7b72=Ta5d6ff"_blank" Te6edf3relTff7b72=Ta5d6ff"noopener"Tb4b4b4>{{ t('footer.firmware') }}Tb4b4b4<Tb4b4b4/Tff7b72aTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"brand.firmwareUrl && brand.sourceUrl"Tb4b4b4>Te6edf3&nbsp;Β·Te6edf3&nbsp;Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72a Te6edf3v-ifTff7b72=Ta5d6ff"brand.sourceUrl" Te6edf3:hrefTff7b72=Ta5d6ff"brand.sourceUrl" Te6edf3targetTff7b72=Ta5d6ff"_blank" Te6edf3relTff7b72=Ta5d6ff"noopener"Tb4b4b4>{{ t('footer.source') }}Tb4b4b4<Tb4b4b4/Tff7b72aTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72footerTb4b4b4>

Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72scriptTb4b4b4>
T8b949e// ══════════════════════════════════════════════════════════════
T8b949e// Screen dump helpers
T8b949e// ══════════════════════════════════════════════════════════════
Tff7b72function Te6edf3frameBufferToCanvasTb4b4b4(Te6edf3bufTb4b4b4, Te6edf3wTb4b4b4, Te6edf3hTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3canvas Tff7b72= Tffa657documentTb4b4b4.Te6edf3createElementTb4b4b4(Ta5d6ff'canvas'Tb4b4b4)Tb4b4b4;
Te6edf3canvasTb4b4b4.Te6edf3width Tff7b72= Te6edf3wTb4b4b4; Te6edf3canvasTb4b4b4.Te6edf3height Tff7b72= Te6edf3hTb4b4b4;
Tff7b72const Te6edf3ctx Tff7b72= Te6edf3canvasTb4b4b4.Te6edf3getContextTb4b4b4(Ta5d6ff'2d'Tb4b4b4)Tb4b4b4;
Te6edf3ctxTb4b4b4.Te6edf3fillStyle Tff7b72= Ta5d6ff'#000'Tb4b4b4; Te6edf3ctxTb4b4b4.Te6edf3fillRectTb4b4b4(T79c0ff0Tb4b4b4, T79c0ff0Tb4b4b4, Te6edf3wTb4b4b4, Te6edf3hTb4b4b4)Tb4b4b4;
Te6edf3ctxTb4b4b4.Te6edf3fillStyle Tff7b72= Ta5d6ff'#07b6e3'Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3y Tff7b72= T79c0ff0Tb4b4b4; Te6edf3y Tff7b72< Te6edf3hTb4b4b4; Te6edf3yTff7b72++Tb4b4b4)
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3x Tff7b72= T79c0ff0Tb4b4b4; Te6edf3x Tff7b72< Te6edf3wTb4b4b4; Te6edf3xTff7b72++Tb4b4b4)
Tff7b72if Tb4b4b4(Tb4b4b4(Te6edf3bufTb4b4b4[Tffa657MathTb4b4b4.Te6edf3floorTb4b4b4(Tb4b4b4(Te6edf3y Tff7b72* Te6edf3w Tff7b72+ Te6edf3xTb4b4b4) Tff7b72/ T79c0ff8Tb4b4b4)Tb4b4b4] Tff7b72>> Tb4b4b4(T79c0ff7 Tff7b72- Tb4b4b4(Te6edf3x Tff7b72% T79c0ff8Tb4b4b4)Tb4b4b4)Tb4b4b4) Tff7b72& T79c0ff1Tb4b4b4)
Te6edf3ctxTb4b4b4.Te6edf3fillRectTb4b4b4(Te6edf3xTb4b4b4, Te6edf3yTb4b4b4, T79c0ff1Tb4b4b4, T79c0ff1Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3canvasTb4b4b4;
Tb4b4b4}
T8b949e// Adafruit_SSD1306's own buffer (what display.getBuffer() returns - see the
T8b949e// raw full-panel format below) uses the controller's native page/column
T8b949e// packing: byte index = x + (y>>3)*w, bit = y&7 (bit0 = top row of an
T8b949e// 8-row "page") - see Adafruit_SSD1306::drawPixel() in the driver source.
T8b949e// That's a different layout from GFXcanvas1 (disp_area/stat_area, what
T8b949e// frameBufferToCanvas above decodes), which packs row-major instead.
Tff7b72function Te6edf3ssd1306BufferToCanvasTb4b4b4(Te6edf3bufTb4b4b4, Te6edf3wTb4b4b4, Te6edf3hTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3canvas Tff7b72= Tffa657documentTb4b4b4.Te6edf3createElementTb4b4b4(Ta5d6ff'canvas'Tb4b4b4)Tb4b4b4;
Te6edf3canvasTb4b4b4.Te6edf3width Tff7b72= Te6edf3wTb4b4b4; Te6edf3canvasTb4b4b4.Te6edf3height Tff7b72= Te6edf3hTb4b4b4;
Tff7b72const Te6edf3ctx Tff7b72= Te6edf3canvasTb4b4b4.Te6edf3getContextTb4b4b4(Ta5d6ff'2d'Tb4b4b4)Tb4b4b4;
Te6edf3ctxTb4b4b4.Te6edf3fillStyle Tff7b72= Ta5d6ff'#000'Tb4b4b4; Te6edf3ctxTb4b4b4.Te6edf3fillRectTb4b4b4(T79c0ff0Tb4b4b4, T79c0ff0Tb4b4b4, Te6edf3wTb4b4b4, Te6edf3hTb4b4b4)Tb4b4b4;
Te6edf3ctxTb4b4b4.Te6edf3fillStyle Tff7b72= Ta5d6ff'#07b6e3'Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3y Tff7b72= T79c0ff0Tb4b4b4; Te6edf3y Tff7b72< Te6edf3hTb4b4b4; Te6edf3yTff7b72++Tb4b4b4)
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3x Tff7b72= T79c0ff0Tb4b4b4; Te6edf3x Tff7b72< Te6edf3wTb4b4b4; Te6edf3xTff7b72++Tb4b4b4)
Tff7b72if Tb4b4b4(Tb4b4b4(Te6edf3bufTb4b4b4[Te6edf3x Tff7b72+ Tb4b4b4(Te6edf3y Tff7b72>> T79c0ff3Tb4b4b4) Tff7b72* Te6edf3wTb4b4b4] Tff7b72>> Tb4b4b4(Te6edf3y Tff7b72& T79c0ff7Tb4b4b4)Tb4b4b4) Tff7b72& T79c0ff1Tb4b4b4)
Te6edf3ctxTb4b4b4.Te6edf3fillRectTb4b4b4(Te6edf3xTb4b4b4, Te6edf3yTb4b4b4, T79c0ff1Tb4b4b4, T79c0ff1Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3canvasTb4b4b4;
Tb4b4b4}
T8b949e// Heltec T096 (product 0xD1) uses a larger 80-wide panel: an 80x64 display
T8b949e// area stacked above a taller 80x96 stat area, instead of the 64x64/64x64
T8b949e// areas placed side by side used by every other board. Heltec T114
T8b949e// (product 0xC2) is bigger still - a 135x110 display area over a 135x130
T8b949e// stat area (full panel width, no side padding), on a 135x240 physical
T8b949e// panel. rawW/rawH is the physical panel size used by the "raw full-panel
T8b949e// buffer" format (see displayBufferToPng) - only meaningful for boards
T8b949e// whose firmware actually sends that format (currently ProMicro/FakeTec,
T8b949e// MeshAdventurer-S3, both a 128x64 monochrome panel); not applicable to
T8b949e// T096/T114, both color panels that always send the disp_area/stat_area
T8b949e// split (format 0x00) since their Settings menu renders into its own
T8b949e// off-screen canvas rather than straight to the panel - see
T8b949e// kiss_indicate_disp(), RNode_Firmware's Utilities.h.
Tff7b72function Te6edf3displayAreaGeometryTb4b4b4(Te6edf3productIdTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3productId Tff7b72=== T79c0ff0xD1Tb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{ Te6edf3dispWTff7b72: T79c0ff80Tb4b4b4, Te6edf3dispHTff7b72: T79c0ff64Tb4b4b4, Te6edf3statWTff7b72: T79c0ff80Tb4b4b4, Te6edf3statHTff7b72: T79c0ff96Tb4b4b4, Te6edf3layoutTff7b72: Ta5d6ff'vertical'Tb4b4b4, Te6edf3rawWTff7b72: T79c0ff80Tb4b4b4, Te6edf3rawHTff7b72: T79c0ff160 Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3productId Tff7b72=== T79c0ff0xC2Tb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{ Te6edf3dispWTff7b72: T79c0ff135Tb4b4b4, Te6edf3dispHTff7b72: T79c0ff110Tb4b4b4, Te6edf3statWTff7b72: T79c0ff135Tb4b4b4, Te6edf3statHTff7b72: T79c0ff130Tb4b4b4, Te6edf3layoutTff7b72: Ta5d6ff'vertical'Tb4b4b4, Te6edf3rawWTff7b72: T79c0ff135Tb4b4b4, Te6edf3rawHTff7b72: T79c0ff240 Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72return Tb4b4b4{ Te6edf3dispWTff7b72: T79c0ff64Tb4b4b4, Te6edf3dispHTff7b72: T79c0ff64Tb4b4b4, Te6edf3statWTff7b72: T79c0ff64Tb4b4b4, Te6edf3statHTff7b72: T79c0ff64Tb4b4b4, Te6edf3layoutTff7b72: Ta5d6ff'horizontal'Tb4b4b4, Te6edf3rawWTff7b72: T79c0ff128Tb4b4b4, Te6edf3rawHTff7b72: T79c0ff64 Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72function Te6edf3displayBufferToPngTb4b4b4(Te6edf3bufTb4b4b4, Te6edf3productIdTb4b4b4) Tb4b4b4{
T8b949e// Devices predating the leading format-byte send the disp_area/stat_area
T8b949e// split with no prefix at all; newer firmware always prepends one byte:
T8b949e// 0x00 = same disp_area/stat_area split, 0x01 = a raw full-panel buffer
T8b949e// (boards with a Settings menu draw the menu straight to the panel,
T8b949e// bypassing disp_area/stat_area - which the split would otherwise show
T8b949e// stale content from - see kiss_indicate_disp()). Tell old-unprefixed
T8b949e// and new-prefixed apart by comparing the total length against this
T8b949e// product's known legacy (disp_area+stat_area) size.
Tff7b72let Tb4b4b4{ Te6edf3dispWTb4b4b4, Te6edf3dispHTb4b4b4, Te6edf3statWTb4b4b4, Te6edf3statHTb4b4b4, Te6edf3layoutTb4b4b4, Te6edf3rawWTb4b4b4, Te6edf3rawH Tb4b4b4} Tff7b72= Te6edf3displayAreaGeometryTb4b4b4(Te6edf3productIdTb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3dispBytes Tff7b72= Tffa657MathTb4b4b4.Te6edf3ceilTb4b4b4(Te6edf3dispW Tff7b72/ T79c0ff8Tb4b4b4) Tff7b72* Te6edf3dispHTb4b4b4;
Tff7b72let Te6edf3statBytes Tff7b72= Tffa657MathTb4b4b4.Te6edf3ceilTb4b4b4(Te6edf3statW Tff7b72/ T79c0ff8Tb4b4b4) Tff7b72* Te6edf3statHTb4b4b4;
Tff7b72let Te6edf3legacyTotal Tff7b72= Te6edf3dispBytes Tff7b72+ Te6edf3statBytesTb4b4b4;

Tff7b72let Te6edf3format Tff7b72= T79c0ff0x00Tb4b4b4;
Tff7b72let Te6edf3payload Tff7b72= Te6edf3bufTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3bufTb4b4b4.Te6edf3length Tff7b72=== Te6edf3legacyTotal Tff7b72+ T79c0ff1Tb4b4b4) Tb4b4b4{
Te6edf3format Tff7b72= Te6edf3bufTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4;
Te6edf3payload Tff7b72= Te6edf3bufTb4b4b4.Te6edf3sliceTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tff7b72if Tb4b4b4(Te6edf3bufTb4b4b4.Te6edf3length Tff7b72!== Te6edf3legacyTotalTb4b4b4) Tb4b4b4{
T8b949e// fall back to the default layout if the buffer doesn't match what we
T8b949e// expected for this product (eg. firmware that predates that layout)
Tb4b4b4(Tb4b4b4{ Te6edf3dispWTb4b4b4, Te6edf3dispHTb4b4b4, Te6edf3statWTb4b4b4, Te6edf3statHTb4b4b4, Te6edf3layoutTb4b4b4, Te6edf3rawWTb4b4b4, Te6edf3rawH Tb4b4b4} Tff7b72= Te6edf3displayAreaGeometryTb4b4b4(Tff7b72nullTb4b4b4)Tb4b4b4)Tb4b4b4;
Te6edf3dispBytes Tff7b72= Tffa657MathTb4b4b4.Te6edf3ceilTb4b4b4(Te6edf3dispW Tff7b72/ T79c0ff8Tb4b4b4) Tff7b72* Te6edf3dispHTb4b4b4;
Te6edf3statBytes Tff7b72= Tffa657MathTb4b4b4.Te6edf3ceilTb4b4b4(Te6edf3statW Tff7b72/ T79c0ff8Tb4b4b4) Tff7b72* Te6edf3statHTb4b4b4;
Te6edf3legacyTotal Tff7b72= Te6edf3dispBytes Tff7b72+ Te6edf3statBytesTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3bufTb4b4b4.Te6edf3length Tff7b72=== Te6edf3legacyTotal Tff7b72+ T79c0ff1Tb4b4b4) Tb4b4b4{
Te6edf3format Tff7b72= Te6edf3bufTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4;
Te6edf3payload Tff7b72= Te6edf3bufTb4b4b4.Te6edf3sliceTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}

Tff7b72let Te6edf3combinedTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3format Tff7b72=== T79c0ff0x01Tb4b4b4) Tb4b4b4{
Te6edf3combined Tff7b72= Te6edf3ssd1306BufferToCanvasTb4b4b4(Te6edf3payloadTb4b4b4, Te6edf3rawWTb4b4b4, Te6edf3rawHTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3combined Tff7b72= Tffa657documentTb4b4b4.Te6edf3createElementTb4b4b4(Ta5d6ff'canvas'Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3layout Tff7b72=== Ta5d6ff'vertical'Tb4b4b4) Tb4b4b4{
Te6edf3combinedTb4b4b4.Te6edf3width Tff7b72= Tffa657MathTb4b4b4.Te6edf3maxTb4b4b4(Te6edf3dispWTb4b4b4, Te6edf3statWTb4b4b4)Tb4b4b4; Te6edf3combinedTb4b4b4.Te6edf3height Tff7b72= Te6edf3dispH Tff7b72+ Te6edf3statHTb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3combinedTb4b4b4.Te6edf3width Tff7b72= Te6edf3dispW Tff7b72+ Te6edf3statWTb4b4b4; Te6edf3combinedTb4b4b4.Te6edf3height Tff7b72= Tffa657MathTb4b4b4.Te6edf3maxTb4b4b4(Te6edf3dispHTb4b4b4, Te6edf3statHTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3ctx Tff7b72= Te6edf3combinedTb4b4b4.Te6edf3getContextTb4b4b4(Ta5d6ff'2d'Tb4b4b4)Tb4b4b4;
Te6edf3ctxTb4b4b4.Te6edf3imageSmoothingEnabled Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72const Te6edf3dispCanvas Tff7b72= Te6edf3frameBufferToCanvasTb4b4b4(Te6edf3payloadTb4b4b4.Te6edf3sliceTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3dispBytesTb4b4b4)Tb4b4b4, Te6edf3dispWTb4b4b4, Te6edf3dispHTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3statCanvas Tff7b72= Te6edf3frameBufferToCanvasTb4b4b4(Te6edf3payloadTb4b4b4.Te6edf3sliceTb4b4b4(Te6edf3dispBytesTb4b4b4, Te6edf3dispBytes Tff7b72+ Te6edf3statBytesTb4b4b4)Tb4b4b4, Te6edf3statWTb4b4b4, Te6edf3statHTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3layout Tff7b72=== Ta5d6ff'vertical'Tb4b4b4) Tb4b4b4{
Te6edf3ctxTb4b4b4.Te6edf3drawImageTb4b4b4(Te6edf3dispCanvasTb4b4b4, T79c0ff0Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4;
Te6edf3ctxTb4b4b4.Te6edf3drawImageTb4b4b4(Te6edf3statCanvasTb4b4b4, T79c0ff0Tb4b4b4, Te6edf3dispHTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3ctxTb4b4b4.Te6edf3drawImageTb4b4b4(Te6edf3dispCanvasTb4b4b4, T79c0ff0Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4;
Te6edf3ctxTb4b4b4.Te6edf3drawImageTb4b4b4(Te6edf3statCanvasTb4b4b4, Te6edf3dispWTb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}

Tff7b72const Te6edf3scaleFactor Tff7b72= T79c0ff4Tb4b4b4;
Tff7b72const Te6edf3scaled Tff7b72= Tffa657documentTb4b4b4.Te6edf3createElementTb4b4b4(Ta5d6ff'canvas'Tb4b4b4)Tb4b4b4;
Te6edf3scaledTb4b4b4.Te6edf3width Tff7b72= Te6edf3combinedTb4b4b4.Te6edf3width Tff7b72* Te6edf3scaleFactorTb4b4b4; Te6edf3scaledTb4b4b4.Te6edf3height Tff7b72= Te6edf3combinedTb4b4b4.Te6edf3height Tff7b72* Te6edf3scaleFactorTb4b4b4;
Tff7b72const Te6edf3sctx Tff7b72= Te6edf3scaledTb4b4b4.Te6edf3getContextTb4b4b4(Ta5d6ff'2d'Tb4b4b4)Tb4b4b4;
Te6edf3sctxTb4b4b4.Te6edf3imageSmoothingEnabled Tff7b72= Tff7b72falseTb4b4b4;
Te6edf3sctxTb4b4b4.Te6edf3drawImageTb4b4b4(Te6edf3combinedTb4b4b4, T79c0ff0Tb4b4b4, T79c0ff0Tb4b4b4, Te6edf3scaledTb4b4b4.Te6edf3widthTb4b4b4, Te6edf3scaledTb4b4b4.Te6edf3heightTb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3scaledTb4b4b4.Te6edf3toDataURLTb4b4b4(Ta5d6ff'image/png'Tb4b4b4)Tb4b4b4;
Tb4b4b4}

T8b949e// ══════════════════════════════════════════════════════════════
T8b949e// Utility
T8b949e// ══════════════════════════════════════════════════════════════
Tff7b72const Te6edf3Utils Tff7b72= Tb4b4b4{
Te6edf3sleepMillisTb4b4b4(Te6edf3msTb4b4b4) Tb4b4b4{ Tff7b72return Tff7b72new Tffa657PromiseTb4b4b4(Te6edf3r Tb4b4b4=> Te6edf3setTimeoutTb4b4b4(Te6edf3rTb4b4b4, Te6edf3msTb4b4b4)Tb4b4b4)Tb4b4b4; Tb4b4b4}Tb4b4b4,
Te6edf3bytesToHexTb4b4b4(Te6edf3bytesTb4b4b4) Tb4b4b4{
Tff7b72let Te6edf3h Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3b Tff7b72of Te6edf3bytesTb4b4b4) Te6edf3h Tff7b72+= Tb4b4b4(Tb4b4b4(Te6edf3b Tff7b72>>> T79c0ff4Tb4b4b4) Tff7b72& T79c0ff0xFTb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4) Tff7b72+ Tb4b4b4(Te6edf3b Tff7b72& T79c0ff0xFTb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3hTb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3md5Tb4b4b4(Te6edf3dataTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3hash Tff7b72= Te6edf3CryptoJSTb4b4b4.Te6edf3MD5Tb4b4b4(Te6edf3CryptoJSTb4b4b4.Te6edf3encTb4b4b4.Te6edf3HexTb4b4b4.Te6edf3parseTb4b4b4(Te6edf3UtilsTb4b4b4.Te6edf3bytesToHexTb4b4b4(Te6edf3dataTb4b4b4)Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3bytes Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3i Tff7b72= T79c0ff0Tb4b4b4; Te6edf3i Tff7b72< Te6edf3hashTb4b4b4.Te6edf3sigBytesTb4b4b4; Te6edf3iTff7b72++Tb4b4b4)
Te6edf3bytesTb4b4b4.Te6edf3pushTb4b4b4(Tb4b4b4(Te6edf3hashTb4b4b4.Te6edf3wordsTb4b4b4[Te6edf3i Tff7b72>>> T79c0ff2Tb4b4b4] Tff7b72>>> Tb4b4b4(T79c0ff24 Tff7b72- Tb4b4b4(Te6edf3i Tff7b72% T79c0ff4Tb4b4b4) Tff7b72* T79c0ff8Tb4b4b4)Tb4b4b4) Tff7b72& T79c0ff0xffTb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3bytesTb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3packUInt32BETb4b4b4(Te6edf3vTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3buf Tff7b72= Tff7b72new Tffa657ArrayBufferTb4b4b4(T79c0ff4Tb4b4b4)Tb4b4b4; Tff7b72new Tffa657DataViewTb4b4b4(Te6edf3bufTb4b4b4)Tb4b4b4.Te6edf3setUint32Tb4b4b4(T79c0ff0Tb4b4b4, Te6edf3vTb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4;
Tff7b72return Tff7b72new Tffa657Uint8ArrayTb4b4b4(Te6edf3bufTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4;

T8b949e// ══════════════════════════════════════════════════════════════
T8b949e// RNode KISS protocol
T8b949e// ══════════════════════════════════════════════════════════════
Tff7b72class Te6edf3RNode Tb4b4b4{
Te6edf3KISS_FEND Tff7b72= T79c0ff0xC0Tb4b4b4; Te6edf3KISS_FESC Tff7b72= T79c0ff0xDBTb4b4b4; Te6edf3KISS_TFEND Tff7b72= T79c0ff0xDCTb4b4b4; Te6edf3KISS_TFESC Tff7b72= T79c0ff0xDDTb4b4b4;
Te6edf3CMD_DETECT Tff7b72= T79c0ff0x08Tb4b4b4; Te6edf3DETECT_REQ Tff7b72= T79c0ff0x73Tb4b4b4; Te6edf3DETECT_RESP Tff7b72= T79c0ff0x46Tb4b4b4;
Te6edf3CMD_LEAVE Tff7b72= T79c0ff0x0ATb4b4b4; Te6edf3LEAVE_BYTE Tff7b72= T79c0ff0xFFTb4b4b4;
Te6edf3CMD_FREQUENCY Tff7b72= T79c0ff0x01Tb4b4b4; Te6edf3CMD_BANDWIDTH Tff7b72= T79c0ff0x02Tb4b4b4; Te6edf3CMD_TXPOWER Tff7b72= T79c0ff0x03Tb4b4b4;
Te6edf3CMD_SF Tff7b72= T79c0ff0x04Tb4b4b4; Te6edf3CMD_CR Tff7b72= T79c0ff0x05Tb4b4b4; Te6edf3CMD_RADIO_STATE Tff7b72= T79c0ff0x06Tb4b4b4;
Te6edf3CMD_TIME Tff7b72= T79c0ff0x81Tb4b4b4;
Te6edf3CMD_PLATFORM Tff7b72= T79c0ff0x48Tb4b4b4;
Te6edf3CMD_FW_VERSION Tff7b72= T79c0ff0x50Tb4b4b4; Te6edf3CMD_ROM_READ Tff7b72= T79c0ff0x51Tb4b4b4; Te6edf3CMD_ROM_WRITE Tff7b72= T79c0ff0x52Tb4b4b4;
Te6edf3CMD_CONF_SAVE Tff7b72= T79c0ff0x53Tb4b4b4; Te6edf3CMD_CONF_DELETE Tff7b72= T79c0ff0x54Tb4b4b4; Te6edf3CMD_RESET Tff7b72= T79c0ff0x55Tb4b4b4; Te6edf3CMD_RESET_BYTE Tff7b72= T79c0ff0xF8Tb4b4b4;
Te6edf3CMD_FW_HASH Tff7b72= T79c0ff0x58Tb4b4b4; Te6edf3CMD_HASHES Tff7b72= T79c0ff0x60Tb4b4b4; Te6edf3CMD_UNLOCK_ROM Tff7b72= T79c0ff0x59Tb4b4b4; Te6edf3CMD_DISP_READ Tff7b72= T79c0ff0x66Tb4b4b4;
Te6edf3CMD_DISP_ROT Tff7b72= T79c0ff0x67Tb4b4b4; Te6edf3CMD_DISP_INT Tff7b72= T79c0ff0x45Tb4b4b4; Te6edf3CMD_DISP_BLNK Tff7b72= T79c0ff0x64Tb4b4b4; Te6edf3CMD_DISP_RCND Tff7b72= T79c0ff0x68Tb4b4b4;
Te6edf3CMD_WIFI_MODE Tff7b72= T79c0ff0x6ATb4b4b4; Te6edf3CMD_WIFI_SSID Tff7b72= T79c0ff0x6BTb4b4b4; Te6edf3CMD_WIFI_PSK Tff7b72= T79c0ff0x6CTb4b4b4;
Te6edf3CMD_WIFI_CHN Tff7b72= T79c0ff0x6ETb4b4b4; Te6edf3CMD_WIFI_IP Tff7b72= T79c0ff0x84Tb4b4b4; Te6edf3CMD_WIFI_NM Tff7b72= T79c0ff0x85Tb4b4b4; Te6edf3CMD_SND Tff7b72= T79c0ff0x86Tb4b4b4; Te6edf3CMD_CFG_READ Tff7b72= T79c0ff0x6DTb4b4b4;
Te6edf3CMD_VSENSE_DIV Tff7b72= T79c0ff0x87Tb4b4b4;
Te6edf3CMD_ETH_IP Tff7b72= T79c0ff0x88Tb4b4b4; Te6edf3CMD_ETH_NM Tff7b72= T79c0ff0x89Tb4b4b4; Te6edf3CMD_ETH_SPEED Tff7b72= T79c0ff0x8ATb4b4b4;
Te6edf3CMD_WIFI_GW Tff7b72= T79c0ff0x8CTb4b4b4; Te6edf3CMD_WIFI_DNS Tff7b72= T79c0ff0x8DTb4b4b4; Te6edf3CMD_ETH_GW Tff7b72= T79c0ff0x8ETb4b4b4; Te6edf3CMD_ETH_DNS Tff7b72= T79c0ff0x8FTb4b4b4;
Te6edf3CMD_NTP_SYNC Tff7b72= T79c0ff0x8BTb4b4b4;
T8b949e// rtc_sync_ntp()'s reason code (RTC.h) - 0 is success, matching C
T8b949e// convention; anything else is a specific failure reason.
Te6edf3NTP_SYNC_OK Tff7b72= T79c0ff0Tb4b4b4; Te6edf3NTP_SYNC_ERR_NO_RTC Tff7b72= T79c0ff1Tb4b4b4; Te6edf3NTP_SYNC_ERR_NO_NET Tff7b72= T79c0ff2Tb4b4b4;
Te6edf3NTP_SYNC_ERR_TIMEOUT Tff7b72= T79c0ff3Tb4b4b4; Te6edf3NTP_SYNC_ERR_RTC_WRITE Tff7b72= T79c0ff4Tb4b4b4;
Te6edf3CMD_BT_CTRL Tff7b72= T79c0ff0x46Tb4b4b4; Te6edf3CMD_BT_PIN Tff7b72= T79c0ff0x62Tb4b4b4;
Te6edf3ROM_UNLOCK_BYTE Tff7b72= T79c0ff0xF8Tb4b4b4; Te6edf3HASH_TYPE_FIRMWARE Tff7b72= T79c0ff0x02Tb4b4b4;

Tff7b72constructorTb4b4b4(Te6edf3portTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3port Tff7b72= Te6edf3portTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3reader Tff7b72= Te6edf3portTb4b4b4.Te6edf3readableTb4b4b4.Te6edf3getReaderTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3writable Tff7b72= Te6edf3portTb4b4b4.Te6edf3writableTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3callbacks Tff7b72= Tb4b4b4{Tb4b4b4}Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3_readLoopTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72static Tff7b72async Te6edf3fromSerialPortTb4b4b4(Te6edf3portTb4b4b4) Tb4b4b4{
Tff7b72await Te6edf3portTb4b4b4.Te6edf3openTb4b4b4(Tb4b4b4{ Te6edf3baudRateTff7b72: T79c0ff115200 Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72return Tff7b72new Te6edf3RNodeTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tb4b4b4}
T8b949e// Connects to an RNode's WebSocket KISS listener (WebSocketRemote.h, port
T8b949e// 7634) instead of USB serial - for browsers, which cannot open raw TCP
T8b949e// sockets and so can't reach the device's raw-TCP KISS relay (Remote.h,
T8b949e// port 7633) directly. The wire bytes are identical KISS frames either
T8b949e// way, so this only needs to adapt the WebSocket into the same
T8b949e// {readable, writable, close()} shape a Web Serial port provides - the
T8b949e// constructor/write()/_readLoop()/close() above are otherwise untouched.
Tff7b72static Tff7b72async Te6edf3fromWebSocketTb4b4b4(Te6edf3urlTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3ws Tff7b72= Tff7b72new Te6edf3WebSocketTb4b4b4(Te6edf3urlTb4b4b4)Tb4b4b4;
Te6edf3wsTb4b4b4.Te6edf3binaryType Tff7b72= Ta5d6ff'arraybuffer'Tb4b4b4;
Tff7b72await Tff7b72new Tffa657PromiseTb4b4b4(Tb4b4b4(Te6edf3resolveTb4b4b4, Te6edf3rejectTb4b4b4) Tb4b4b4=> Tb4b4b4{
Te6edf3wsTb4b4b4.Te6edf3addEventListenerTb4b4b4(Ta5d6ff'open'Tb4b4b4, Tb4b4b4(Tb4b4b4) Tb4b4b4=> Te6edf3resolveTb4b4b4(Tb4b4b4)Tb4b4b4, Tb4b4b4{ Te6edf3onceTff7b72: Tff7b72true Tb4b4b4}Tb4b4b4)Tb4b4b4;
Te6edf3wsTb4b4b4.Te6edf3addEventListenerTb4b4b4(Ta5d6ff'error'Tb4b4b4, Tb4b4b4(Tb4b4b4) Tb4b4b4=> Te6edf3rejectTb4b4b4(Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'WebSocket connection failed'Tb4b4b4)Tb4b4b4)Tb4b4b4, Tb4b4b4{ Te6edf3onceTff7b72: Tff7b72true Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3readable Tff7b72= Tff7b72new Te6edf3ReadableStreamTb4b4b4(Tb4b4b4{
Te6edf3startTb4b4b4(Te6edf3controllerTb4b4b4) Tb4b4b4{
Te6edf3wsTb4b4b4.Te6edf3addEventListenerTb4b4b4(Ta5d6ff'message'Tb4b4b4, Tb4b4b4(Te6edf3eventTb4b4b4) Tb4b4b4=> Te6edf3controllerTb4b4b4.Te6edf3enqueueTb4b4b4(Tff7b72new Tffa657Uint8ArrayTb4b4b4(Te6edf3eventTb4b4b4.Te6edf3dataTb4b4b4)Tb4b4b4)Tb4b4b4)Tb4b4b4;
Te6edf3wsTb4b4b4.Te6edf3addEventListenerTb4b4b4(Ta5d6ff'close'Tb4b4b4, Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{ Tff7b72try Tb4b4b4{ Te6edf3controllerTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4} Tb4b4b4}Tb4b4b4)Tb4b4b4;
Te6edf3wsTb4b4b4.Te6edf3addEventListenerTb4b4b4(Ta5d6ff'error'Tb4b4b4, Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{ Tff7b72try Tb4b4b4{ Te6edf3controllerTb4b4b4.Te6edf3errorTb4b4b4(Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'WebSocket error'Tb4b4b4)Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4} Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3writable Tff7b72= Tff7b72new Te6edf3WritableStreamTb4b4b4(Tb4b4b4{
Te6edf3writeTb4b4b4(Te6edf3chunkTb4b4b4) Tb4b4b4{ Te6edf3wsTb4b4b4.Te6edf3sendTb4b4b4(Te6edf3chunkTb4b4b4)Tb4b4b4; Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72return Tff7b72new Te6edf3RNodeTb4b4b4(Tb4b4b4{
Te6edf3readableTb4b4b4,
Te6edf3writableTb4b4b4,
Te6edf3closeTff7b72: Tff7b72async Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{ Te6edf3wsTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3closeTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3readerTb4b4b4.Te6edf3cancelTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72try Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3readerTb4b4b4.Te6edf3releaseLockTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72try Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4}
Tff7b72async Te6edf3writeTb4b4b4(Te6edf3bytesTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3w Tff7b72= Tff7b72thisTb4b4b4.Te6edf3writableTb4b4b4.Te6edf3getWriterTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3wTb4b4b4.Te6edf3writeTb4b4b4(Tff7b72new Tffa657Uint8ArrayTb4b4b4(Te6edf3bytesTb4b4b4)Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72finally Tb4b4b4{ Te6edf3wTb4b4b4.Te6edf3releaseLockTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tb4b4b4}
Tff7b72async Te6edf3_readLoopTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72let Te6edf3buf Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4, Te6edf3inFrame Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72while Tb4b4b4(Tff7b72trueTb4b4b4) Tb4b4b4{
Tff7b72const Tb4b4b4{ Te6edf3valueTb4b4b4, Te6edf3done Tb4b4b4} Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3readerTb4b4b4.Te6edf3readTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3doneTb4b4b4) Tff7b72breakTb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3b Tff7b72of Te6edf3valueTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3b Tff7b72=== Tff7b72thisTb4b4b4.Te6edf3KISS_FENDTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3inFrameTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3frame Tff7b72= Tff7b72thisTb4b4b4.Te6edf3_decodeKissTb4b4b4(Te6edf3bufTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3frameTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3_onCmdTb4b4b4(Te6edf3frameTb4b4b4)Tb4b4b4;
Te6edf3buf Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tb4b4b4}
Te6edf3inFrame Tff7b72= Tff7b72!Te6edf3inFrameTb4b4b4;
Tb4b4b4} Tff7b72else Tff7b72if Tb4b4b4(Te6edf3inFrameTb4b4b4) Te6edf3bufTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3bTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tb4b4b4(Te6edf3e Tff7b72instanceof Tf85149TypeErrorTb4b4b4)Tb4b4b4) Te6edf3consoleTb4b4b4.Te6edf3warnTb4b4b4(Ta5d6ff'RNode read loop:'Tb4b4b4, Te6edf3eTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72finally Tb4b4b4{ Tff7b72try Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3readerTb4b4b4.Te6edf3releaseLockTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4} Tb4b4b4}
Tb4b4b4}
Te6edf3_decodeKissTb4b4b4(Te6edf3frameTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3out Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4; Tff7b72let Te6edf3esc Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3b Tff7b72of Te6edf3frameTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3escTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3b Tff7b72=== Tff7b72thisTb4b4b4.Te6edf3KISS_TFENDTb4b4b4) Te6edf3outTb4b4b4.Te6edf3pushTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3KISS_FENDTb4b4b4)Tb4b4b4;
Tff7b72else Tff7b72if Tb4b4b4(Te6edf3b Tff7b72=== Tff7b72thisTb4b4b4.Te6edf3KISS_TFESCTb4b4b4) Te6edf3outTb4b4b4.Te6edf3pushTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3KISS_FESCTb4b4b4)Tb4b4b4;
Tff7b72else Tff7b72return Tff7b72nullTb4b4b4;
Te6edf3esc Tff7b72= Tff7b72falseTb4b4b4;
Tb4b4b4} Tff7b72else Tff7b72if Tb4b4b4(Te6edf3b Tff7b72=== Tff7b72thisTb4b4b4.Te6edf3KISS_FESCTb4b4b4) Te6edf3esc Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72else Te6edf3outTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3bTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72return Te6edf3esc Tff7b72? Tff7b72null Tff7b72: Te6edf3outTb4b4b4;
Tb4b4b4}
Te6edf3_encodeKissTb4b4b4(Te6edf3dataTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3f Tff7b72= Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3KISS_FENDTb4b4b4]Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3b Tff7b72of Te6edf3dataTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3b Tff7b72=== Tff7b72thisTb4b4b4.Te6edf3KISS_FENDTb4b4b4) Te6edf3fTb4b4b4.Te6edf3pushTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3KISS_FESCTb4b4b4, Tff7b72thisTb4b4b4.Te6edf3KISS_TFENDTb4b4b4)Tb4b4b4;
Tff7b72else Tff7b72if Tb4b4b4(Te6edf3b Tff7b72=== Tff7b72thisTb4b4b4.Te6edf3KISS_FESCTb4b4b4) Te6edf3fTb4b4b4.Te6edf3pushTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3KISS_FESCTb4b4b4, Tff7b72thisTb4b4b4.Te6edf3KISS_TFESCTb4b4b4)Tb4b4b4;
Tff7b72else Te6edf3fTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3bTb4b4b4)Tb4b4b4;
Tb4b4b4}
Te6edf3fTb4b4b4.Te6edf3pushTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3KISS_FENDTb4b4b4)Tb4b4b4;
Tff7b72return Tff7b72new Tffa657Uint8ArrayTb4b4b4(Te6edf3fTb4b4b4)Tb4b4b4;
Tb4b4b4}
Te6edf3_onCmdTb4b4b4(Te6edf3dataTb4b4b4) Tb4b4b4{
Tff7b72const Tb4b4b4[Te6edf3cmdTb4b4b4, Tb4b4b4...Te6edf3bytesTb4b4b4] Tff7b72= Te6edf3dataTb4b4b4;
Tff7b72const Te6edf3cb Tff7b72= Tff7b72thisTb4b4b4.Te6edf3callbacksTb4b4b4[Te6edf3cmdTb4b4b4]Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3cbTb4b4b4) Tb4b4b4{ Te6edf3cbTb4b4b4(Te6edf3bytesTb4b4b4)Tb4b4b4; Tff7b72delete Tff7b72thisTb4b4b4.Te6edf3callbacksTb4b4b4[Te6edf3cmdTb4b4b4]Tb4b4b4; Tb4b4b4}
Tb4b4b4}
Tff7b72async Te6edf3sendCmdTb4b4b4(Te6edf3cmdTb4b4b4, Te6edf3dataTb4b4b4, Te6edf3timeoutMs Tff7b72= T79c0ff3000Tb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72new Tffa657PromiseTb4b4b4(Tff7b72async Tb4b4b4(Te6edf3resolveTb4b4b4, Te6edf3rejectTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72const Te6edf3t Tff7b72= Te6edf3setTimeoutTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72delete Tff7b72thisTb4b4b4.Te6edf3callbacksTb4b4b4[Te6edf3cmdTb4b4b4]Tb4b4b4;
Te6edf3rejectTb4b4b4(Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff`Ta5d6fftimeout waiting for response to 0xTffd700${Te6edf3cmdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff2Tb4b4b4,Ta5d6ff'0'Tb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4, Te6edf3timeoutMsTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3callbacksTb4b4b4[Te6edf3cmdTb4b4b4] Tff7b72= Tb4b4b4(Te6edf3bytesTb4b4b4) Tb4b4b4=> Tb4b4b4{ Te6edf3clearTimeoutTb4b4b4(Te6edf3tTb4b4b4)Tb4b4b4; Te6edf3resolveTb4b4b4(Te6edf3bytesTb4b4b4)Tb4b4b4; Tb4b4b4}Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3writeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3_encodeKissTb4b4b4(Tb4b4b4[Te6edf3cmdTb4b4b4, Tb4b4b4...Te6edf3dataTb4b4b4]Tb4b4b4)Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Te6edf3clearTimeoutTb4b4b4(Te6edf3tTb4b4b4)Tb4b4b4; Tff7b72delete Tff7b72thisTb4b4b4.Te6edf3callbacksTb4b4b4[Te6edf3cmdTb4b4b4]Tb4b4b4; Te6edf3rejectTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4; Tb4b4b4}
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3sendKissOnlyTb4b4b4(Te6edf3dataTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3writeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3_encodeKissTb4b4b4(Te6edf3dataTb4b4b4)Tb4b4b4)Tb4b4b4; Tb4b4b4}

Tff7b72async Te6edf3detectTb4b4b4(Te6edf3timeoutMs Tff7b72= T79c0ff2500Tb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72new Tffa657PromiseTb4b4b4(Tff7b72async Te6edf3resolve Tb4b4b4=> Tb4b4b4{
Tff7b72const Te6edf3t Tff7b72= Te6edf3setTimeoutTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Te6edf3resolveTb4b4b4(Tff7b72falseTb4b4b4)Tb4b4b4, Te6edf3timeoutMsTb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3resp Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_DETECTTb4b4b4, Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3DETECT_REQTb4b4b4]Tb4b4b4)Tb4b4b4;
Te6edf3clearTimeoutTb4b4b4(Te6edf3tTb4b4b4)Tb4b4b4;
Te6edf3resolveTb4b4b4(Te6edf3respTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72=== Tff7b72thisTb4b4b4.Te6edf3DETECT_RESPTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Te6edf3clearTimeoutTb4b4b4(Te6edf3tTb4b4b4)Tb4b4b4; Te6edf3resolveTb4b4b4(Tff7b72falseTb4b4b4)Tb4b4b4; Tb4b4b4}
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3getFirmwareVersionTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3resp Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_FW_VERSIONTb4b4b4, Tb4b4b4[T79c0ff0x00Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3minor Tff7b72= Te6edf3respTb4b4b4[T79c0ff1Tb4b4b4]Tb4b4b4;
Tff7b72if Tb4b4b4(Tffa657StringTb4b4b4(Te6edf3minorTb4b4b4)Tb4b4b4.Te6edf3length Tff7b72=== T79c0ff1Tb4b4b4) Te6edf3minor Tff7b72= Ta5d6ff'0' Tff7b72+ Te6edf3minorTb4b4b4;
Tff7b72let Te6edf3version Tff7b72= Te6edf3respTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72+ Ta5d6ff'.' Tff7b72+ Te6edf3minorTb4b4b4;
T8b949e// Newer firmware appends a 4-byte big-endian BUILD_NUMBER (git commit
T8b949e// count) after the original 2-byte MAJ_VERS/MIN_VERS payload, same
T8b949e// "1.86.947" format used in the flasher's own firmware version.txt.
T8b949e// Older firmware only ever sends the 2-byte payload.
Tff7b72if Tb4b4b4(Te6edf3respTb4b4b4.Te6edf3length Tff7b72>= T79c0ff6Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3build Tff7b72= Tb4b4b4(Tb4b4b4(Te6edf3respTb4b4b4[T79c0ff2Tb4b4b4] Tff7b72<< T79c0ff24Tb4b4b4) Tff7b72| Tb4b4b4(Te6edf3respTb4b4b4[T79c0ff3Tb4b4b4] Tff7b72<< T79c0ff16Tb4b4b4) Tff7b72| Tb4b4b4(Te6edf3respTb4b4b4[T79c0ff4Tb4b4b4] Tff7b72<< T79c0ff8Tb4b4b4) Tff7b72| Te6edf3respTb4b4b4[T79c0ff5Tb4b4b4]Tb4b4b4) Tff7b72>>> T79c0ff0Tb4b4b4;
Te6edf3version Tff7b72+= Ta5d6ff'.' Tff7b72+ Te6edf3buildTb4b4b4;
Tb4b4b4}
Tff7b72return Te6edf3versionTb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3getPlatformTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3resp Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_PLATFORMTb4b4b4, Tb4b4b4[T79c0ff0x00Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3respTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3getRomTb4b4b4(Te6edf3timeoutMs Tff7b72= T79c0ff3000Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3resp Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_ROM_READTb4b4b4, Tb4b4b4[T79c0ff0x00Tb4b4b4]Tb4b4b4, Te6edf3timeoutMsTb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3respTb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3getWifiConfigTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3resp Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_CFG_READTb4b4b4, Tb4b4b4[T79c0ff0x00Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3respTb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3writeRomTb4b4b4(Te6edf3addrTb4b4b4, Te6edf3valTb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_ROM_WRITETb4b4b4, Te6edf3addrTb4b4b4, Te6edf3valTb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff85Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3getFirmwareHashTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3resp Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_HASHESTb4b4b4, Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3HASH_TYPE_FIRMWARETb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3respTb4b4b4.Te6edf3sliceTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3setFirmwareHashTb4b4b4(Te6edf3hashTb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_FW_HASHTb4b4b4, Tb4b4b4...Te6edf3hashTb4b4b4]Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3wipeRomTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_UNLOCK_ROMTb4b4b4, Tff7b72thisTb4b4b4.Te6edf3ROM_UNLOCK_BYTETb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff30000Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3resetTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_RESETTb4b4b4, Tff7b72thisTb4b4b4.Te6edf3CMD_RESET_BYTETb4b4b4]Tb4b4b4)Tb4b4b4;
Tb4b4b4}
T8b949e// tell the firmware the host is detaching: marks the RNS link
T8b949e// disconnected, unblanks the display and resets signal stats
Tff7b72async Te6edf3leaveTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_LEAVETb4b4b4, Tff7b72thisTb4b4b4.Te6edf3LEAVE_BYTETb4b4b4]Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3readDisplayTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3resp Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_DISP_READTb4b4b4, Tb4b4b4[T79c0ff0x01Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3respTb4b4b4;
Tb4b4b4}

T8b949e// ── Radio read ──────────────────────────────────────────────
Tff7b72async Te6edf3getFrequencyTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3r Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_FREQUENCYTb4b4b4, Tb4b4b4[T79c0ff0Tb4b4b4,T79c0ff0Tb4b4b4,T79c0ff0Tb4b4b4,T79c0ff0Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72return Tb4b4b4(Te6edf3rTb4b4b4[T79c0ff0Tb4b4b4]Tff7b72<<T79c0ff24Tff7b72|Te6edf3rTb4b4b4[T79c0ff1Tb4b4b4]Tff7b72<<T79c0ff16Tff7b72|Te6edf3rTb4b4b4[T79c0ff2Tb4b4b4]Tff7b72<<T79c0ff8Tff7b72|Te6edf3rTb4b4b4[T79c0ff3Tb4b4b4]Tb4b4b4) Tff7b72>>> T79c0ff0Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3getBandwidthTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3r Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_BANDWIDTHTb4b4b4, Tb4b4b4[T79c0ff0Tb4b4b4,T79c0ff0Tb4b4b4,T79c0ff0Tb4b4b4,T79c0ff0Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72return Tb4b4b4(Te6edf3rTb4b4b4[T79c0ff0Tb4b4b4]Tff7b72<<T79c0ff24Tff7b72|Te6edf3rTb4b4b4[T79c0ff1Tb4b4b4]Tff7b72<<T79c0ff16Tff7b72|Te6edf3rTb4b4b4[T79c0ff2Tb4b4b4]Tff7b72<<T79c0ff8Tff7b72|Te6edf3rTb4b4b4[T79c0ff3Tb4b4b4]Tb4b4b4) Tff7b72>>> T79c0ff0Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3getTxPowerTb4b4b4(Tb4b4b4) Tb4b4b4{ Tff7b72return Tb4b4b4(Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_TXPOWERTb4b4b4, Tb4b4b4[T79c0ff0xFFTb4b4b4]Tb4b4b4)Tb4b4b4)Tb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3getSpreadingFactorTb4b4b4(Tb4b4b4) Tb4b4b4{ Tff7b72return Tb4b4b4(Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_SFTb4b4b4, Tb4b4b4[T79c0ff0xFFTb4b4b4]Tb4b4b4)Tb4b4b4)Tb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3getCodingRateTb4b4b4(Tb4b4b4) Tb4b4b4{ Tff7b72return Tb4b4b4(Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_CRTb4b4b4, Tb4b4b4[T79c0ff0xFFTb4b4b4]Tb4b4b4)Tb4b4b4)Tb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4; Tb4b4b4}

T8b949e// ── Radio write ─────────────────────────────────────────────
Te6edf3_be32Tb4b4b4(Te6edf3vTb4b4b4) Tb4b4b4{ Tff7b72return Tb4b4b4[Te6edf3vTff7b72>>>T79c0ff24Tff7b72&T79c0ff0xFFTb4b4b4, Te6edf3vTff7b72>>>T79c0ff16Tff7b72&T79c0ff0xFFTb4b4b4, Te6edf3vTff7b72>>>T79c0ff8Tff7b72&T79c0ff0xFFTb4b4b4, Te6edf3vTff7b72&T79c0ff0xFFTb4b4b4]Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setFrequencyTb4b4b4(Te6edf3hzTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_FREQUENCYTb4b4b4, Tb4b4b4...Tff7b72thisTb4b4b4.Te6edf3_be32Tb4b4b4(Te6edf3hzTb4b4b4)Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setBandwidthTb4b4b4(Te6edf3hzTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_BANDWIDTHTb4b4b4, Tb4b4b4...Tff7b72thisTb4b4b4.Te6edf3_be32Tb4b4b4(Te6edf3hzTb4b4b4)Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setTxPowerTb4b4b4(Te6edf3dbTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_TXPOWERTb4b4b4, Te6edf3dbTb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setSpreadingFactorTb4b4b4(Te6edf3sfTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_SFTb4b4b4, Te6edf3sfTb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setCodingRateTb4b4b4(Te6edf3crTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_CRTb4b4b4, Te6edf3crTb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setRadioStateTb4b4b4(Te6edf3onTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_RADIO_STATETb4b4b4, Te6edf3on Tff7b72? T79c0ff0x01 Tff7b72: T79c0ff0x00Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3saveConfigTb4b4b4(Tb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_CONF_SAVETb4b4b4, T79c0ff0x00Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3deleteConfigTb4b4b4(Tb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_CONF_DELETETb4b4b4, T79c0ff0x00Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}

T8b949e// ── Display write ────────────────────────────────────────────
Tff7b72async Te6edf3setDisplayRotationTb4b4b4(Te6edf3rTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_DISP_ROTTb4b4b4, Te6edf3r Tff7b72& T79c0ff0xFFTb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setDisplayIntensityTb4b4b4(Te6edf3iTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_DISP_INTTb4b4b4, Te6edf3i Tff7b72& T79c0ff0xFFTb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setDisplayTimeoutTb4b4b4(Te6edf3tTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_DISP_BLNKTb4b4b4, Te6edf3t Tff7b72& T79c0ff0xFFTb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3reconditionDisplayTb4b4b4(Tb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_DISP_RCNDTb4b4b4, T79c0ff0x01Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}

T8b949e// ── WiFi write ───────────────────────────────────────────────
Tff7b72async Te6edf3setWifiModeTb4b4b4(Te6edf3modeTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_WIFI_MODETb4b4b4, Te6edf3modeTb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setWifiChannelTb4b4b4(Te6edf3chTb4b4b4)Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_WIFI_CHNTb4b4b4, Te6edf3chTb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setWifiSsidTb4b4b4(Te6edf3ssidTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3b Tff7b72= Tff7b72new Te6edf3TextEncoderTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3encodeTb4b4b4(Te6edf3ssidTb4b4b4)Tb4b4b4;
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_WIFI_SSIDTb4b4b4, Tb4b4b4...Te6edf3bTb4b4b4, T79c0ff0x00Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3setWifiPskTb4b4b4(Te6edf3pskTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3pskTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_WIFI_PSKTb4b4b4, T79c0ff0x00Tb4b4b4]Tb4b4b4)Tb4b4b4; Tff7b72returnTb4b4b4; Tb4b4b4}
Tff7b72const Te6edf3b Tff7b72= Tff7b72new Te6edf3TextEncoderTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3encodeTb4b4b4(Te6edf3pskTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3bTb4b4b4.Te6edf3length Tff7b72< T79c0ff8 Tff7b72|| Te6edf3bTb4b4b4.Te6edf3length Tff7b72> T79c0ff32Tb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'PSK must be 8–32 characters'Tb4b4b4)Tb4b4b4;
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_WIFI_PSKTb4b4b4, Tb4b4b4...Te6edf3bTb4b4b4, T79c0ff0x00Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Te6edf3_parseIpTb4b4b4(Te6edf3sTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3p Tff7b72= Te6edf3sTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3splitTb4b4b4(Ta5d6ff'.'Tb4b4b4)Tb4b4b4.Te6edf3mapTb4b4b4(Tffa657NumberTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3pTb4b4b4.Te6edf3length Tff7b72!== T79c0ff4 Tff7b72|| Te6edf3pTb4b4b4.Te6edf3someTb4b4b4(Te6edf3n Tb4b4b4=> Tffa657isNaNTb4b4b4(Te6edf3nTb4b4b4)Tff7b72||Te6edf3nTff7b72<T79c0ff0Tff7b72||Te6edf3nTff7b72>T79c0ff255Tb4b4b4)Tb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff`Ta5d6ffInvalid address: Tffd700${Te6edf3sTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3pTb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3setWifiIpTb4b4b4(Te6edf3ipTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_WIFI_IPTb4b4b4, Tb4b4b4...Tff7b72thisTb4b4b4.Te6edf3_parseIpTb4b4b4(Te6edf3ipTb4b4b4)Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setWifiNmTb4b4b4(Te6edf3nmTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_WIFI_NMTb4b4b4, Tb4b4b4...Tff7b72thisTb4b4b4.Te6edf3_parseIpTb4b4b4(Te6edf3nmTb4b4b4)Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setWifiGwTb4b4b4(Te6edf3gwTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_WIFI_GWTb4b4b4, Tb4b4b4...Tff7b72thisTb4b4b4.Te6edf3_parseIpTb4b4b4(Te6edf3gwTb4b4b4)Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setWifiDnsTb4b4b4(Te6edf3dnsTb4b4b4)Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_WIFI_DNSTb4b4b4, Tb4b4b4...Tff7b72thisTb4b4b4.Te6edf3_parseIpTb4b4b4(Te6edf3dnsTb4b4b4)Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}

T8b949e// ── Ethernet write ──────────────────────────────────────────
Tff7b72async Te6edf3setEthIpTb4b4b4(Te6edf3ipTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_ETH_IPTb4b4b4, Tb4b4b4...Tff7b72thisTb4b4b4.Te6edf3_parseIpTb4b4b4(Te6edf3ipTb4b4b4)Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setEthNmTb4b4b4(Te6edf3nmTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_ETH_NMTb4b4b4, Tb4b4b4...Tff7b72thisTb4b4b4.Te6edf3_parseIpTb4b4b4(Te6edf3nmTb4b4b4)Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setEthGwTb4b4b4(Te6edf3gwTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_ETH_GWTb4b4b4, Tb4b4b4...Tff7b72thisTb4b4b4.Te6edf3_parseIpTb4b4b4(Te6edf3gwTb4b4b4)Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setEthDnsTb4b4b4(Te6edf3dnsTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_ETH_DNSTb4b4b4, Tb4b4b4...Tff7b72thisTb4b4b4.Te6edf3_parseIpTb4b4b4(Te6edf3dnsTb4b4b4)Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setEthSpeedTb4b4b4(Te6edf3modeTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_ETH_SPEEDTb4b4b4, Te6edf3modeTb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}

Tff7b72async Te6edf3setSoundTb4b4b4(Te6edf3onTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_SNDTb4b4b4, Te6edf3on Tff7b72? T79c0ff0x01 Tff7b72: T79c0ff0x00Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3setVsenseDividerTb4b4b4(Te6edf3ratioTb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_VSENSE_DIVTb4b4b4, Tffa657MathTb4b4b4.Te6edf3roundTb4b4b4(Te6edf3ratio Tff7b72* T79c0ff10Tb4b4b4) Tff7b72& T79c0ff0xFFTb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}

T8b949e// ── RTC (HAS_RTC boards only) ────────────────────────────────
T8b949e// CMD_TIME reads back the RTC's current unixtime either way: a 0
T8b949e// payload requests a read, any other 4-byte value sets the clock and
T8b949e// echoes the (now current) reading - 0 back means no RTC chip present.
Tff7b72async Te6edf3getTimeTb4b4b4(Te6edf3timeoutMs Tff7b72= T79c0ff3000Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3r Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_TIMETb4b4b4, Tb4b4b4[T79c0ff0Tb4b4b4, T79c0ff0Tb4b4b4, T79c0ff0Tb4b4b4, T79c0ff0Tb4b4b4]Tb4b4b4, Te6edf3timeoutMsTb4b4b4)Tb4b4b4;
Tff7b72return Tb4b4b4(Te6edf3rTb4b4b4[T79c0ff0Tb4b4b4]Tff7b72<<T79c0ff24 Tff7b72| Te6edf3rTb4b4b4[T79c0ff1Tb4b4b4]Tff7b72<<T79c0ff16 Tff7b72| Te6edf3rTb4b4b4[T79c0ff2Tb4b4b4]Tff7b72<<T79c0ff8 Tff7b72| Te6edf3rTb4b4b4[T79c0ff3Tb4b4b4]Tb4b4b4) Tff7b72>>> T79c0ff0Tb4b4b4;
Tb4b4b4}
Tff7b72async Te6edf3setTimeTb4b4b4(Te6edf3epochSecondsTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3r Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_TIMETb4b4b4, Tff7b72thisTb4b4b4.Te6edf3_be32Tb4b4b4(Te6edf3epochSecondsTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72return Tb4b4b4(Te6edf3rTb4b4b4[T79c0ff0Tb4b4b4]Tff7b72<<T79c0ff24 Tff7b72| Te6edf3rTb4b4b4[T79c0ff1Tb4b4b4]Tff7b72<<T79c0ff16 Tff7b72| Te6edf3rTb4b4b4[T79c0ff2Tb4b4b4]Tff7b72<<T79c0ff8 Tff7b72| Te6edf3rTb4b4b4[T79c0ff3Tb4b4b4]Tb4b4b4) Tff7b72>>> T79c0ff0Tb4b4b4;
Tb4b4b4}
T8b949e// Blocks on-device for up to NTP_SYNC_TIMEOUT_MS (RTC.h, 5s) while it
T8b949e// resolves and queries pool.ntp.org, so give it a generous timeout.
T8b949e// Replies under its own command byte (kiss_indicate_ntp_sync(), firmware
T8b949e// Utilities.h) with a leading status byte (NTP_SYNC_OK/NTP_SYNC_ERR_*
T8b949e// above - 0 means success) followed by the 4-byte epoch, not just a
T8b949e// bare epoch like CMD_TIME's response.
Tff7b72async Te6edf3syncNtpTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3r Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendCmdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3CMD_NTP_SYNCTb4b4b4, Tb4b4b4[T79c0ff0x01Tb4b4b4]Tb4b4b4, T79c0ff10000Tb4b4b4)Tb4b4b4;
Tff7b72return Tb4b4b4{ Te6edf3statusTff7b72: Te6edf3rTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4, Te6edf3epochTff7b72: Tb4b4b4(Te6edf3rTb4b4b4[T79c0ff1Tb4b4b4]Tff7b72<<T79c0ff24 Tff7b72| Te6edf3rTb4b4b4[T79c0ff2Tb4b4b4]Tff7b72<<T79c0ff16 Tff7b72| Te6edf3rTb4b4b4[T79c0ff3Tb4b4b4]Tff7b72<<T79c0ff8 Tff7b72| Te6edf3rTb4b4b4[T79c0ff4Tb4b4b4]Tb4b4b4) Tff7b72>>> T79c0ff0 Tb4b4b4}Tb4b4b4;
Tb4b4b4}

Tff7b72async Te6edf3enableBluetoothTb4b4b4(Tb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_BT_CTRLTb4b4b4, T79c0ff0x01Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3disableBluetoothTb4b4b4(Tb4b4b4) Tb4b4b4{ Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_BT_CTRLTb4b4b4, T79c0ff0x00Tb4b4b4]Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72async Te6edf3pairBluetoothTb4b4b4(Te6edf3timeoutMs Tff7b72= T79c0ff30000Tb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72new Tffa657PromiseTb4b4b4(Tff7b72async Tb4b4b4(Te6edf3resolveTb4b4b4, Te6edf3rejectTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72const Te6edf3t Tff7b72= Te6edf3setTimeoutTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72delete Tff7b72thisTb4b4b4.Te6edf3callbacksTb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_BT_PINTb4b4b4]Tb4b4b4;
Te6edf3rejectTb4b4b4(Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'pairing timeout β€” no device connected within 30 s'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4, Te6edf3timeoutMsTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3callbacksTb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_BT_PINTb4b4b4] Tff7b72= Tb4b4b4(Te6edf3bytesTb4b4b4) Tb4b4b4=> Tb4b4b4{
Te6edf3clearTimeoutTb4b4b4(Te6edf3tTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3pin Tff7b72= Tb4b4b4(Tb4b4b4(Te6edf3bytesTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72<< T79c0ff24Tb4b4b4) Tff7b72| Tb4b4b4(Te6edf3bytesTb4b4b4[T79c0ff1Tb4b4b4] Tff7b72<< T79c0ff16Tb4b4b4) Tff7b72| Tb4b4b4(Te6edf3bytesTb4b4b4[T79c0ff2Tb4b4b4] Tff7b72<< T79c0ff8Tb4b4b4) Tff7b72| Te6edf3bytesTb4b4b4[T79c0ff3Tb4b4b4]Tb4b4b4) Tff7b72>>> T79c0ff0Tb4b4b4;
Te6edf3resolveTb4b4b4(Tffa657StringTb4b4b4(Te6edf3pinTb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff6Tb4b4b4, Ta5d6ff'0'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4;
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3sendKissOnlyTb4b4b4(Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3CMD_BT_CTRLTb4b4b4, T79c0ff0x02Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}

T8b949e// ══════════════════════════════════════════════════════════════
T8b949e// ROM constants & parser
T8b949e// ══════════════════════════════════════════════════════════════
Tff7b72const Te6edf3ROM Tff7b72= Tb4b4b4{
Te6edf3ADDR_PRODUCTTff7b72: T79c0ff0x00Tb4b4b4, Te6edf3ADDR_MODELTff7b72: T79c0ff0x01Tb4b4b4, Te6edf3ADDR_HW_REVTff7b72: T79c0ff0x02Tb4b4b4,
Te6edf3ADDR_SERIALTff7b72: T79c0ff0x03Tb4b4b4, Te6edf3ADDR_MADETff7b72: T79c0ff0x07Tb4b4b4, Te6edf3ADDR_CHKSUMTff7b72: T79c0ff0x0BTb4b4b4,
Te6edf3ADDR_SIGNATURETff7b72: T79c0ff0x1BTb4b4b4, Te6edf3ADDR_INFO_LOCKTff7b72: T79c0ff0x9BTb4b4b4,
Te6edf3PLATFORM_AVRTff7b72: T79c0ff0x90Tb4b4b4, Te6edf3PLATFORM_ESP32Tff7b72: T79c0ff0x80Tb4b4b4, Te6edf3PLATFORM_NRF52Tff7b72: T79c0ff0x70Tb4b4b4,
Te6edf3ADDR_CONF_SFTff7b72: T79c0ff0x9CTb4b4b4, Te6edf3ADDR_CONF_CRTff7b72: T79c0ff0x9DTb4b4b4, Te6edf3ADDR_CONF_TXPTff7b72: T79c0ff0x9ETb4b4b4,
Te6edf3ADDR_CONF_BWTff7b72: T79c0ff0x9FTb4b4b4, Te6edf3ADDR_CONF_FREQTff7b72: T79c0ff0xA3Tb4b4b4, Te6edf3ADDR_CONF_OKTff7b72: T79c0ff0xA7Tb4b4b4,
Te6edf3ADDR_CONF_BTTff7b72: T79c0ff0xB0Tb4b4b4,
Te6edf3ADDR_CONF_DSETTff7b72: T79c0ff0xB1Tb4b4b4, Te6edf3ADDR_CONF_DINTTff7b72: T79c0ff0xB2Tb4b4b4, Te6edf3ADDR_CONF_DBLKTff7b72: T79c0ff0xB4Tb4b4b4,
Te6edf3ADDR_CONF_BSETTff7b72: T79c0ff0xB7Tb4b4b4, Te6edf3ADDR_CONF_DROTTff7b72: T79c0ff0xB8Tb4b4b4,
Te6edf3ADDR_CONF_WIFITff7b72: T79c0ff0xBATb4b4b4, Te6edf3ADDR_CONF_WCHNTff7b72: T79c0ff0xBBTb4b4b4, Te6edf3ADDR_CONF_SNDTff7b72: T79c0ff0xBCTb4b4b4,
Te6edf3ADDR_CONF_VSRTff7b72: T79c0ff0xBDTb4b4b4, Te6edf3ADDR_CONF_ETHSPDTff7b72: T79c0ff0xC4Tb4b4b4,
Te6edf3ETH_SPEED_AUTOTff7b72: T79c0ff0x00Tb4b4b4, Te6edf3ETH_SPEED_100_FULLTff7b72: T79c0ff0x01Tb4b4b4, Te6edf3ETH_SPEED_100_HALFTff7b72: T79c0ff0x02Tb4b4b4,
Te6edf3ETH_SPEED_10_FULLTff7b72: T79c0ff0x03Tb4b4b4, Te6edf3ETH_SPEED_10_HALFTff7b72: T79c0ff0x04Tb4b4b4, Te6edf3ETH_SPEED_OFFTff7b72: T79c0ff0x05Tb4b4b4,
T8b949e// Config-area offsets (returned by CMD_CFG_READ, separate 256-byte partition)
Te6edf3CFG_SSIDTff7b72: T79c0ff0x00Tb4b4b4, Te6edf3CFG_PSKTff7b72: T79c0ff0x21Tb4b4b4, Te6edf3CFG_IPTff7b72: T79c0ff0x42Tb4b4b4, Te6edf3CFG_NMTff7b72: T79c0ff0x46Tb4b4b4,
Te6edf3CFG_ETH_IPTff7b72: T79c0ff0x4ATb4b4b4, Te6edf3CFG_ETH_NMTff7b72: T79c0ff0x4ETb4b4b4,
Te6edf3CFG_GWTff7b72: T79c0ff0x52Tb4b4b4, Te6edf3CFG_DNSTff7b72: T79c0ff0x56Tb4b4b4, Te6edf3CFG_ETH_GWTff7b72: T79c0ff0x5ATb4b4b4, Te6edf3CFG_ETH_DNSTff7b72: T79c0ff0x5ETb4b4b4,
Te6edf3INFO_LOCK_BYTETff7b72: T79c0ff0x73Tb4b4b4, Te6edf3CONF_OK_BYTETff7b72: T79c0ff0x73Tb4b4b4,

Te6edf3isProvisionedTb4b4b4(Te6edf3eepromTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3eepromTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_INFO_LOCKTb4b4b4] Tff7b72!== Te6edf3ROMTb4b4b4.Te6edf3INFO_LOCK_BYTETb4b4b4) Tff7b72return Tff7b72falseTb4b4b4;
Tff7b72const Te6edf3calc Tff7b72= Te6edf3UtilsTb4b4b4.Te6edf3md5Tb4b4b4(Tb4b4b4[
Te6edf3eepromTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_PRODUCTTb4b4b4]Tb4b4b4, Te6edf3eepromTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_MODELTb4b4b4]Tb4b4b4, Te6edf3eepromTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_HW_REVTb4b4b4]Tb4b4b4,
Tb4b4b4...Tffa657ArrayTb4b4b4.Tff7b72fromTb4b4b4(Tb4b4b4{Te6edf3lengthTff7b72:T79c0ff4Tb4b4b4}Tb4b4b4, Tb4b4b4(Te6edf3_Tb4b4b4,Te6edf3iTb4b4b4) Tb4b4b4=> Te6edf3eepromTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_SERIAL Tff7b72+ Te6edf3iTb4b4b4]Tb4b4b4)Tb4b4b4,
Tb4b4b4...Tffa657ArrayTb4b4b4.Tff7b72fromTb4b4b4(Tb4b4b4{Te6edf3lengthTff7b72:T79c0ff4Tb4b4b4}Tb4b4b4, Tb4b4b4(Te6edf3_Tb4b4b4,Te6edf3iTb4b4b4) Tb4b4b4=> Te6edf3eepromTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_MADE Tff7b72+ Te6edf3iTb4b4b4]Tb4b4b4)Tb4b4b4,
Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3stored Tff7b72= Tffa657ArrayTb4b4b4.Tff7b72fromTb4b4b4(Tb4b4b4{Te6edf3lengthTff7b72:T79c0ff16Tb4b4b4}Tb4b4b4, Tb4b4b4(Te6edf3_Tb4b4b4,Te6edf3iTb4b4b4) Tb4b4b4=> Te6edf3eepromTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CHKSUM Tff7b72+ Te6edf3iTb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3UtilsTb4b4b4.Te6edf3bytesToHexTb4b4b4(Te6edf3calcTb4b4b4) Tff7b72=== Te6edf3UtilsTb4b4b4.Te6edf3bytesToHexTb4b4b4(Te6edf3storedTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4;

T8b949e// ══════════════════════════════════════════════════════════════
T8b949e// Device database
T8b949e// ══════════════════════════════════════════════════════════════
Tff7b72const Te6edf3C Tff7b72= Ta5d6ff'/firmware/classic/latest/'Tb4b4b4;
Tff7b72const Te6edf3MR Tff7b72= Ta5d6ff'/firmware/microreticulum/latest/'Tb4b4b4;
Tff7b72const Te6edf3RT Tff7b72= Ta5d6ff'/firmware/rtnode/latest/'Tb4b4b4;
Tff7b72const Te6edf3MSH Tff7b72= Ta5d6ff'/firmware/meshtastic/latest/'Tb4b4b4;
Tff7b72const Te6edf3MC Tff7b72= Ta5d6ff'/firmware/meshcore/latest/'Tb4b4b4;
Tff7b72const Te6edf3ERASE Tff7b72= Ta5d6ff'/firmware/erase/latest/'Tb4b4b4;

T8b949e// USB VIDs used by nRF52 boards in both application and bootloader mode
T8b949e// (Adafruit, Nordic, Seeed). Shared by DFU-mode detection/re-enumeration
T8b949e// and by the platform check in eraseFlash().
Tff7b72const Te6edf3NRF52_VIDS Tff7b72= Tb4b4b4[T79c0ff0x239aTb4b4b4, T79c0ff0x1915Tb4b4b4, T79c0ff0x2886Tb4b4b4]Tb4b4b4;

T8b949e// A small non-interactive app (github: see ~/Development/nRF52-Eraser) that
T8b949e// wipes the internal LittleFS settings/bonding partition on any
T8b949e// Adafruit-bootloader nRF52840 board and reboots straight back into the UF2
T8b949e// bootloader. Previously-flashed firmware (Meshtastic, RNode, etc.) can
T8b949e// leave that partition in a state that prevents a later firmware from
T8b949e// booting cleanly, so flashAll() always erases it first for nRF52 boards,
T8b949e// and eraseFlash() flashes it directly when the erase button is used on an
T8b949e// nRF52 device.
Tff7b72const Te6edf3NRF52_ERASER_ZIP Tff7b72= Te6edf3ERASE Tff7b72+ Ta5d6ff'nRF52_Universal_Eraser_DFU.zip'Tb4b4b4;

T8b949e// Speeds espConnect() tries, fastest first. Anything past the first entry
T8b949e// is a Windows workaround: older ESP32-D0WD boards (DIY-V1) behind a
T8b949e// CP2102 do not reliably survive the switch to 921600 there, while the
T8b949e// same board flashes fine on Linux. See espConnect() for the details.
Tff7b72const Te6edf3ESP_BAUD_LADDER Tff7b72= Tb4b4b4[T79c0ff921600Tb4b4b4, T79c0ff460800Tb4b4b4, T79c0ff115200Tb4b4b4]Tb4b4b4;

T8b949e// Time given to the OS/driver to deliver whatever it buffered across the
T8b949e// port close/re-open of a baud switch, before that buffer is dropped.
Tff7b72const Te6edf3ESP_BAUD_SETTLE_MS Tff7b72= T79c0ff250Tb4b4b4;

Tff7b72function Te6edf3fcTb4b4b4(Te6edf3nameTb4b4b4, Te6edf3szTb4b4b4, Te6edf3boot0Tb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{
Te6edf3flash_sizeTff7b72: Te6edf3szTb4b4b4,
Te6edf3flash_filesTff7b72: Tb4b4b4{
Ta5d6ff'0xe000'Tff7b72: Ta5d6ff`Tffd700${Te6edf3nameTffd700}Ta5d6ff.boot_app0Ta5d6ff`Tb4b4b4,
Tb4b4b4[Te6edf3boot0 Tff7b72? Ta5d6ff'0x0' Tff7b72: Ta5d6ff'0x1000'Tb4b4b4]Tff7b72: Ta5d6ff`Tffd700${Te6edf3nameTffd700}Ta5d6ff.bootloaderTa5d6ff`Tb4b4b4,
Ta5d6ff'0x10000'Tff7b72: Ta5d6ff`Tffd700${Te6edf3nameTffd700}Ta5d6ff.binTa5d6ff`Tb4b4b4,
Ta5d6ff'0x210000'Tff7b72: Ta5d6ff'console_image.bin'Tb4b4b4,
Ta5d6ff'0x8000'Tff7b72: Ta5d6ff`Tffd700${Te6edf3nameTffd700}Ta5d6ff.partitionsTa5d6ff`Tb4b4b4,
Tb4b4b4}
Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72function Te6edf3fcRTTb4b4b4(Te6edf3szTb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{
Te6edf3flash_sizeTff7b72: Te6edf3szTb4b4b4,
Te6edf3flash_filesTff7b72: Tb4b4b4{
Ta5d6ff'0xe000'Tff7b72: Ta5d6ff'boot_app0.bin'Tb4b4b4, Ta5d6ff'0x0'Tff7b72: Ta5d6ff'bootloader.bin'Tb4b4b4,
Ta5d6ff'0x10000'Tff7b72: Ta5d6ff'firmware.bin'Tb4b4b4, Ta5d6ff'0x8000'Tff7b72: Ta5d6ff'partitions.bin'Tb4b4b4,
Tb4b4b4}
Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72function Te6edf3fcRTMergedTb4b4b4(Te6edf3nameTb4b4b4, Te6edf3szTb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{ Te6edf3flash_sizeTff7b72: Te6edf3szTb4b4b4, Te6edf3flash_filesTff7b72: Tb4b4b4{ Ta5d6ff'0x0'Tff7b72: Te6edf3name Tb4b4b4} Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72function Te6edf3fcMSHTb4b4b4(Te6edf3szTb4b4b4, Te6edf3newBootTb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{
Te6edf3flash_sizeTff7b72: Te6edf3szTb4b4b4,
Te6edf3flash_filesTff7b72: Tb4b4b4{
Tb4b4b4[Te6edf3newBoot Tff7b72? Ta5d6ff'0x0' Tff7b72: Ta5d6ff'0x1000'Tb4b4b4]Tff7b72: Ta5d6ff'bootloader.bin'Tb4b4b4,
Ta5d6ff'0x8000'Tff7b72: Ta5d6ff'partitions.bin'Tb4b4b4, Ta5d6ff'0x10000'Tff7b72: Ta5d6ff'firmware.bin'Tb4b4b4,
Tb4b4b4}
Tb4b4b4}Tb4b4b4;
Tb4b4b4}

Tff7b72function Te6edf3vTb4b4b4(Te6edf3nameTb4b4b4, Te6edf3model_idTb4b4b4, Te6edf3zipTb4b4b4, Te6edf3configTb4b4b4, Te6edf3provTff7b72=Tff7b72trueTb4b4b4, Te6edf3mapped_model_idTff7b72=Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{ Te6edf3nameTb4b4b4, Te6edf3model_idTb4b4b4, Te6edf3mapped_model_idTb4b4b4, Te6edf3firmware_zipTff7b72: Te6edf3zipTb4b4b4, Te6edf3flash_configTff7b72: Te6edf3configTb4b4b4, Te6edf3needs_provisioningTff7b72: Te6edf3provTb4b4b4, Te6edf3platformTff7b72: Ta5d6ff'esp32' Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72function Te6edf3vnTb4b4b4(Te6edf3nameTb4b4b4, Te6edf3model_idTb4b4b4, Te6edf3zipTb4b4b4, Te6edf3provTff7b72=Tff7b72trueTb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{ Te6edf3nameTb4b4b4, Te6edf3model_idTb4b4b4, Te6edf3firmware_zipTff7b72: Te6edf3zipTb4b4b4, Te6edf3needs_provisioningTff7b72: Te6edf3provTb4b4b4, Te6edf3platformTff7b72: Ta5d6ff'nrf52' Tb4b4b4}Tb4b4b4;
Tb4b4b4}

Tff7b72const Te6edf3DEVICE_GROUPS Tff7b72= Tb4b4b4[
Tb4b4b4{
Te6edf3labelTff7b72: Ta5d6ff'Heltec'Tb4b4b4,
Te6edf3devicesTff7b72: Tb4b4b4[
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'Heltec LoRa32 v2'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xC0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xC4Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_heltec32v2.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_heltec32v2'Tb4b4b4,Ta5d6ff'8MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xC9Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_heltec32v2.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_heltec32v2'Tb4b4b4,Ta5d6ff'8MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” MicroReticulum'Tb4b4b4, T79c0ff0xC4Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_heltec32v2.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_heltec32v2'Tb4b4b4,Ta5d6ff'8MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” MicroReticulum'Tb4b4b4,T79c0ff0xC9Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_heltec32v2.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_heltec32v2'Tb4b4b4,Ta5d6ff'8MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'Heltec LoRa32 v3'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xC1Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xC5Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_heltec32v3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_heltec32v3'Tb4b4b4,Ta5d6ff'8MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xCATb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_heltec32v3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_heltec32v3'Tb4b4b4,Ta5d6ff'8MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” MicroReticulum'Tb4b4b4, T79c0ff0xC5Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_heltec32v3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_heltec32v3'Tb4b4b4,Ta5d6ff'8MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” MicroReticulum'Tb4b4b4,T79c0ff0xCATb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_heltec32v3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_heltec32v3'Tb4b4b4,Ta5d6ff'8MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RTNode'Tb4b4b4, T79c0ff0xCATb4b4b4, Te6edf3RTTff7b72+Ta5d6ff'rtnode_heltec_v3.zip'Tb4b4b4, Te6edf3fcRTMergedTb4b4b4(Ta5d6ff'rtnode_heltec_v3_merged.bin'Tb4b4b4,Ta5d6ff'8MB'Tb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'Heltec LoRa32 v4'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xC3Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xC8Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_heltec32v4pa.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_heltec32v4pa'Tb4b4b4,Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” MicroReticulum'Tb4b4b4,T79c0ff0xC8Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_heltec32v4pa.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_heltec32v4pa'Tb4b4b4,Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RTNode'Tb4b4b4, T79c0ff0xC8Tb4b4b4, Te6edf3RTTff7b72+Ta5d6ff'rtnode_heltec_v4.zip'Tb4b4b4, Te6edf3fcRTMergedTb4b4b4(Ta5d6ff'rtnode_heltec_v4_merged.bin'Tb4b4b4,Ta5d6ff'16MB'Tb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'Heltec T114'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xC2Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vnTb4b4b4(Ta5d6ff'470-510 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xC6Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_heltec_t114.zip'Tb4b4b4)Tb4b4b4,
Te6edf3vnTb4b4b4(Ta5d6ff'863-928 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xC7Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_heltec_t114.zip'Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'Heltec T096'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xD1Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vnTb4b4b4(Ta5d6ff'470-510 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xD3Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_heltec_t096.zip'Tb4b4b4)Tb4b4b4,
Te6edf3vnTb4b4b4(Ta5d6ff'863-928 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xD5Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_heltec_t096.zip'Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3labelTff7b72: Ta5d6ff'LilyGO'Tb4b4b4,
Te6edf3devicesTff7b72: Tb4b4b4[
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'LilyGO LoRa32 v1.0'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xB2Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xBATb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_lora32v10.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v10'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xBBTb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_lora32v10.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v10'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” MicroReticulum'Tb4b4b4, T79c0ff0xBATb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_lora32v10.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v10'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” MicroReticulum'Tb4b4b4,T79c0ff0xBBTb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_lora32v10.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v10'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'LilyGO LoRa32 v2.0'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xB0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xB3Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_lora32v20.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v20'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xB8Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_lora32v20.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v20'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” MicroReticulum'Tb4b4b4, T79c0ff0xB3Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_lora32v20.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v20'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” MicroReticulum'Tb4b4b4,T79c0ff0xB8Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_lora32v20.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v20'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'LilyGO LoRa32 v2.1'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xB1Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xB4Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_lora32v21.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v21'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xB9Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_lora32v21.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v21'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz TCXO β€” RNode Classic'Tb4b4b4, T79c0ff0x04Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_lora32v21_tcxo.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v21_tcxo'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4, Tff7b72trueTb4b4b4, T79c0ff0xB4Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz TCXO β€” RNode Classic'Tb4b4b4, T79c0ff0x09Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_lora32v21_tcxo.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v21_tcxo'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4, Tff7b72trueTb4b4b4, T79c0ff0xB9Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” MicroReticulum'Tb4b4b4, T79c0ff0xB4Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_lora32v21.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v21'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” MicroReticulum'Tb4b4b4, T79c0ff0xB9Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_lora32v21.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_lora32v21'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'LilyGO T3S3'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0x03Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz SX1278 β€” RNode Classic'Tb4b4b4, T79c0ff0xA5Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_t3s3_sx127x.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_t3s3_sx127x'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz SX1276 β€” Classic'Tb4b4b4, T79c0ff0xAATb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_t3s3_sx127x.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_t3s3_sx127x'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz SX1268 β€” RNode Classic'Tb4b4b4, T79c0ff0xA1Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_t3s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_t3s3'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz SX1262 β€” Classic'Tb4b4b4, T79c0ff0xA6Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_t3s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_t3s3'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'2.4 GHz SX1280 β€” RNode Classic'Tb4b4b4, T79c0ff0xACTb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_t3s3_sx1280_pa.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_t3s3_sx1280_pa'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz SX1278 β€” MicroReticulum'Tb4b4b4, T79c0ff0xA5Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_t3s3_sx127x.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_t3s3_sx127x'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz SX1276 β€” MicroReticulum'Tb4b4b4, T79c0ff0xAATb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_t3s3_sx127x.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_t3s3_sx127x'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz SX1268 β€” MicroReticulum'Tb4b4b4, T79c0ff0xA1Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_t3s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_t3s3'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz SX1262 β€” MicroReticulum'Tb4b4b4, T79c0ff0xA6Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_t3s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_t3s3'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'LilyGO T-Beam'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xE0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz SX1278 β€” RNode Classic'Tb4b4b4, T79c0ff0xE4Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_tbeam.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz SX1276 β€” Classic'Tb4b4b4, T79c0ff0xE9Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_tbeam.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz SX1268 β€” RNode Classic'Tb4b4b4, T79c0ff0xE3Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_tbeam_sx1262.zip'Tb4b4b4,Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_sx1262'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz SX1262 β€” Classic'Tb4b4b4, T79c0ff0xE8Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_tbeam_sx1262.zip'Tb4b4b4,Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_sx1262'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz SX1278 β€” MicroReticulum'Tb4b4b4, T79c0ff0xE4Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_tbeam.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz SX1276 β€” MicroReticulum'Tb4b4b4, T79c0ff0xE9Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_tbeam.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz SX1268 β€” MicroReticulum'Tb4b4b4, T79c0ff0xE3Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_tbeam_sx1262.zip'Tb4b4b4,Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_sx1262'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz SX1262 β€” MicroReticulum'Tb4b4b4, T79c0ff0xE8Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_tbeam_sx1262.zip'Tb4b4b4,Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_sx1262'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'LilyGO T-Beam Supreme'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xEATb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xDBTb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_tbeam_supreme.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_supreme'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xDCTb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_tbeam_supreme.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_supreme'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” MicroReticulum'Tb4b4b4, T79c0ff0xDBTb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_tbeam_supreme.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_supreme'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” MicroReticulum'Tb4b4b4,T79c0ff0xDCTb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_tbeam_supreme.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_supreme'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'LilyGO T-Beam Supreme V3'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xECTb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xDBTb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_tbeam_supreme_v3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_supreme_v3'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xDCTb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_tbeam_supreme_v3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_supreme_v3'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” MicroReticulum'Tb4b4b4, T79c0ff0xDBTb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_tbeam_supreme.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_supreme'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” MicroReticulum'Tb4b4b4,T79c0ff0xDCTb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_tbeam_supreme.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tbeam_supreme'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'LilyGO T-Deck'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xD0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xD4Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_tdeck.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tdeck'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xD9Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_tdeck.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tdeck'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” MicroReticulum'Tb4b4b4, T79c0ff0xD4Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_tdeck.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tdeck'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” MicroReticulum'Tb4b4b4,T79c0ff0xD9Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_tdeck.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_tdeck'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'LilyGO T-Echo'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0x15Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vnTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0x16Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_techo.zip'Tb4b4b4)Tb4b4b4,
Te6edf3vnTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0x17Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_techo.zip'Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3labelTff7b72: Ta5d6ff'Seeed'Tb4b4b4,
Te6edf3devicesTff7b72: Tb4b4b4[
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'Xiao ESP32S3'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xEBTb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xDETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_xiao_esp32s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_xiao_esp32s3'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xDDTb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_xiao_esp32s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_xiao_esp32s3'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” MicroReticulum'Tb4b4b4, T79c0ff0xDETb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_xiao_esp32s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_xiao_esp32s3'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” MicroReticulum'Tb4b4b4,T79c0ff0xDDTb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_xiao_esp32s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_xiao_esp32s3'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3labelTff7b72: Ta5d6ff'Community'Tb4b4b4,
Te6edf3devicesTff7b72: Tb4b4b4[
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'MeshAdventurer-S3'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xF0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_meshadventurer_s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_meshadventurer_s3'Tb4b4b4,Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_meshadventurer_s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_meshadventurer_s3'Tb4b4b4,Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RTNode'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3RTTff7b72+Ta5d6ff'rtnode_meshadventurer_s3.zip'Tb4b4b4, Te6edf3fcRTTb4b4b4(Ta5d6ff'16MB'Tb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'Meshtastic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3MSHTff7b72+Ta5d6ff'meshtastic_firmware_meshadventurer-s3.zip'Tb4b4b4, Te6edf3fcMSHTb4b4b4(Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'MeshPoE-S3'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xF0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_meshpoe_s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_meshpoe_s3'Tb4b4b4,Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_meshpoe_s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_meshpoe_s3'Tb4b4b4,Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'Meshtastic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3MSHTff7b72+Ta5d6ff'meshtastic_firmware_meshpoe-s3.zip'Tb4b4b4, Te6edf3fcMSHTb4b4b4(Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'MeshCore β€” Companion (BLE)'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3MCTff7b72+Ta5d6ff'meshcore_firmware_meshpoe-s3_companion_radio_ble.zip'Tb4b4b4, Te6edf3fcMSHTb4b4b4(Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'MeshCore β€” Companion (USB)'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3MCTff7b72+Ta5d6ff'meshcore_firmware_meshpoe-s3_companion_radio_usb.zip'Tb4b4b4, Te6edf3fcMSHTb4b4b4(Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'MeshCore β€” Companion (WiFi)'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3MCTff7b72+Ta5d6ff'meshcore_firmware_meshpoe-s3_companion_radio_wifi.zip'Tb4b4b4, Te6edf3fcMSHTb4b4b4(Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'MeshCore β€” Repeater'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3MCTff7b72+Ta5d6ff'meshcore_firmware_meshpoe-s3_repeater.zip'Tb4b4b4, Te6edf3fcMSHTb4b4b4(Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'MeshCore β€” Repeater Bridge (ESP-NOW)'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3MCTff7b72+Ta5d6ff'meshcore_firmware_meshpoe-s3_repeater_bridge_espnow.zip'Tb4b4b4, Te6edf3fcMSHTb4b4b4(Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'MeshCore β€” Room Server'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3MCTff7b72+Ta5d6ff'meshcore_firmware_meshpoe-s3_room_server.zip'Tb4b4b4, Te6edf3fcMSHTb4b4b4(Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'MeshCore β€” KISS Modem'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3MCTff7b72+Ta5d6ff'meshcore_firmware_meshpoe-s3_kiss_modem.zip'Tb4b4b4, Te6edf3fcMSHTb4b4b4(Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'Aethernode-S3'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xF0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_aethernode_s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_aethernode_s3'Tb4b4b4,Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_aethernode_s3.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_aethernode_s3'Tb4b4b4,Ta5d6ff'16MB'Tb4b4b4,Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'Aethernode'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xF0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_aethernode.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_aethernode'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'Meshtastic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3MSHTff7b72+Ta5d6ff'meshtastic_firmware_aethernode.zip'Tb4b4b4, Te6edf3fcMSHTb4b4b4(Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'MeshAdventurer'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xF0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_meshadventurer.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_meshadventurer'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz 30dBm β€” Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_meshadventurer.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_meshadventurer'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'868/915/923 MHz 33dBm β€” Classic'Tb4b4b4, T79c0ff0xFDTb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_meshadventurer.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_meshadventurer'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'Merged Binary β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_meshadventurer_merged.zip'Tb4b4b4, Tb4b4b4{Te6edf3flash_sizeTff7b72:Ta5d6ff'4MB'Tb4b4b4,Te6edf3flash_filesTff7b72:Tb4b4b4{Ta5d6ff'0x0'Tff7b72:Ta5d6ff'rnode_firmware_meshadventurer_merged.bin'Tb4b4b4}Tb4b4b4}Tb4b4b4, Tff7b72trueTb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'DIY-V1'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xF0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'470-510 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_diy_v1.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_diy_v1'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'863-928 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_diy_v1.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_diy_v1'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'FakeTec (Promicro/nice!nano)'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xF0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vnTb4b4b4(Ta5d6ff'863-928 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_promicro.zip'Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'Aethermobi'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0xF0Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vnTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0xFETb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_promicro.zip'Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3labelTff7b72: Ta5d6ff'RAK'Tb4b4b4,
Te6edf3devicesTff7b72: Tb4b4b4[
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'RAK4631'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0x10Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vnTb4b4b4(Ta5d6ff'433 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0x11Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_rak4631.zip'Tb4b4b4)Tb4b4b4,
Te6edf3vnTb4b4b4(Ta5d6ff'868/915/923 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0x12Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_rak4631.zip'Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3labelTff7b72: Ta5d6ff'SenseCAP'Tb4b4b4,
Te6edf3devicesTff7b72: Tb4b4b4[
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'SenseCAP T1000E'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0x24Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vnTb4b4b4(Ta5d6ff'863-928 MHz β€” RNode Classic'Tb4b4b4, T79c0ff0x25Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_t1000e.zip'Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Te6edf3labelTff7b72: Ta5d6ff'Original RNode'Tb4b4b4,
Te6edf3devicesTff7b72: Tb4b4b4[
Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff'RNode NG (v2.0 / v2.1)'Tb4b4b4,
Te6edf3product_idTff7b72: T79c0ff0x03Tb4b4b4,
Te6edf3variantsTff7b72: Tb4b4b4[
Te6edf3vTb4b4b4(Ta5d6ff'410-525 MHz v2.0 β€” RNode Classic'Tb4b4b4, T79c0ff0xA2Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_ng20.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_ng20'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'820-1020 MHz v2.0 β€” RNode Classic'Tb4b4b4, T79c0ff0xA7Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_ng20.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_ng20'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'410-525 MHz v2.1 β€” RNode Classic'Tb4b4b4, T79c0ff0xA2Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_ng21.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_ng21'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'820-1020 MHz v2.1 β€” RNode Classic'Tb4b4b4, T79c0ff0xA7Tb4b4b4, Te6edf3CTff7b72+Ta5d6ff'rnode_firmware_ng21.zip'Tb4b4b4, Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_ng21'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'410-525 MHz v2.0 β€” MicroReticulum'Tb4b4b4, T79c0ff0xA2Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_ng20.zip'Tb4b4b4,Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_ng20'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'820-1020 MHz v2.0 β€” MicroReticulum'Tb4b4b4,T79c0ff0xA7Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_ng20.zip'Tb4b4b4,Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_ng20'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'410-525 MHz v2.1 β€” MicroReticulum'Tb4b4b4, T79c0ff0xA2Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_ng21.zip'Tb4b4b4,Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_ng21'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3vTb4b4b4(Ta5d6ff'820-1020 MHz v2.1 β€” MicroReticulum'Tb4b4b4,T79c0ff0xA7Tb4b4b4, Te6edf3MRTff7b72+Ta5d6ff'rnode_firmware_ng21.zip'Tb4b4b4,Te6edf3fcTb4b4b4(Ta5d6ff'rnode_firmware_ng21'Tb4b4b4,Ta5d6ff'4MB'Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4]
Tb4b4b4}Tb4b4b4,
Tb4b4b4]Tb4b4b4;

T8b949e// chip, flash size, and optional USB vendor ID for hardware fingerprinting
Tff7b72const Te6edf3DEVICE_HARDWARE Tff7b72= Tb4b4b4{
T8b949e// ESP32
Ta5d6ff'Heltec LoRa32 v2'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'8MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'Heltec LoRa32 v3'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32-S3'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'8MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'Heltec LoRa32 v4'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32-S3'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'16MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO LoRa32 v1.0'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO LoRa32 v2.0'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO LoRa32 v2.1'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T3S3'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32-S3'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T-Beam'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T-Beam Supreme'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32-S3'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T-Beam Supreme V3'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32-S3'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T-Deck'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32-S3'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'Xiao ESP32S3'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32-S3'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'MeshAdventurer-S3'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32-S3'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'16MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'MeshPoE-S3'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32-S3'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'16MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'Aethernode-S3'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32-S3'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'16MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'Aethernode'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'MeshAdventurer'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'DIY-V1'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
Ta5d6ff'RNode NG (v2.0 / v2.1)'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'ESP32'Tb4b4b4, Te6edf3flashTff7b72: Ta5d6ff'4MB' Tb4b4b4}Tb4b4b4,
T8b949e// nRF52 (Flash size not detectable via Web Serial, omitted)
Ta5d6ff'Heltec T114'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'nRF52' Tb4b4b4}Tb4b4b4,
Ta5d6ff'Heltec T096'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'nRF52' Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T-Echo'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'nRF52' Tb4b4b4}Tb4b4b4,
Ta5d6ff'FakeTec (Promicro/nice!nano)'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'nRF52' Tb4b4b4}Tb4b4b4,
Ta5d6ff'Aethermobi'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'nRF52' Tb4b4b4}Tb4b4b4,
Ta5d6ff'RAK4631'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'nRF52' Tb4b4b4}Tb4b4b4,
Ta5d6ff'SenseCAP T1000E'Tff7b72: Tb4b4b4{ Te6edf3chipTff7b72: Ta5d6ff'nRF52' Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4;

T8b949e// ══════════════════════════════════════════════════════════════
T8b949e// Direct-link URI scheme (?d=<device>&v=<variant>)
T8b949e//
T8b949e// Device ids are hand-picked short codes (stable, rarely change).
T8b949e// Variant ids are derived automatically from the variant name so
T8b949e// new variants get a working link without maintaining a table β€”
T8b949e// see variantShortId() below. Uniqueness is only required within
T8b949e// a single device's variant list, not globally.
T8b949e// ══════════════════════════════════════════════════════════════
Tff7b72const Te6edf3DEVICE_SHORT_ID Tff7b72= Tb4b4b4{
Ta5d6ff'Heltec LoRa32 v2'Tff7b72: Ta5d6ff'htc-lora32v2'Tb4b4b4,
Ta5d6ff'Heltec LoRa32 v3'Tff7b72: Ta5d6ff'htc-lora32v3'Tb4b4b4,
Ta5d6ff'Heltec LoRa32 v4'Tff7b72: Ta5d6ff'htc-lora32v4'Tb4b4b4,
Ta5d6ff'Heltec T114'Tff7b72: Ta5d6ff'htc-t114'Tb4b4b4,
Ta5d6ff'Heltec T096'Tff7b72: Ta5d6ff'htc-t096'Tb4b4b4,
Ta5d6ff'LilyGO LoRa32 v1.0'Tff7b72: Ta5d6ff'lyg-lora32v1'Tb4b4b4,
Ta5d6ff'LilyGO LoRa32 v2.0'Tff7b72: Ta5d6ff'lyg-lora32v2'Tb4b4b4,
Ta5d6ff'LilyGO LoRa32 v2.1'Tff7b72: Ta5d6ff'lyg-lora32v21'Tb4b4b4,
Ta5d6ff'LilyGO T3S3'Tff7b72: Ta5d6ff'lyg-t3s3'Tb4b4b4,
Ta5d6ff'LilyGO T-Beam'Tff7b72: Ta5d6ff'lyg-tbeam'Tb4b4b4,
Ta5d6ff'LilyGO T-Beam Supreme'Tff7b72: Ta5d6ff'lyg-tbeamsup'Tb4b4b4,
Ta5d6ff'LilyGO T-Beam Supreme V3'Tff7b72: Ta5d6ff'lyg-tbeamsupv3'Tb4b4b4,
Ta5d6ff'LilyGO T-Deck'Tff7b72: Ta5d6ff'lyg-tdeck'Tb4b4b4,
Ta5d6ff'LilyGO T-Echo'Tff7b72: Ta5d6ff'lyg-techo'Tb4b4b4,
Ta5d6ff'Xiao ESP32S3'Tff7b72: Ta5d6ff'xiao-esp32s3'Tb4b4b4,
Ta5d6ff'MeshAdventurer-S3'Tff7b72: Ta5d6ff'meshadv-s3'Tb4b4b4,
Ta5d6ff'MeshPoE-S3'Tff7b72: Ta5d6ff'meshpoe-s3'Tb4b4b4,
Ta5d6ff'Aethernode-S3'Tff7b72: Ta5d6ff'aethernode-s3'Tb4b4b4,
Ta5d6ff'Aethernode'Tff7b72: Ta5d6ff'aethernode'Tb4b4b4,
Ta5d6ff'MeshAdventurer'Tff7b72: Ta5d6ff'meshadv'Tb4b4b4,
Ta5d6ff'DIY-V1'Tff7b72: Ta5d6ff'diy-v1'Tb4b4b4,
Ta5d6ff'FakeTec (Promicro/nice!nano)'Tff7b72: Ta5d6ff'faketec'Tb4b4b4,
Ta5d6ff'Aethermobi'Tff7b72: Ta5d6ff'aethermobi'Tb4b4b4,
Ta5d6ff'RAK4631'Tff7b72: Ta5d6ff'rak4631'Tb4b4b4,
Ta5d6ff'SenseCAP T1000E'Tff7b72: Ta5d6ff'sensecap-t1000e'Tb4b4b4,
Ta5d6ff'RNode NG (v2.0 / v2.1)'Tff7b72: Ta5d6ff'rnode-ng'Tb4b4b4,
Tb4b4b4}Tb4b4b4;

Tff7b72const Te6edf3VARIANT_SLUG_ABBR Tff7b72= Tb4b4b4[
Tb4b4b4[Ta5d6ff/rnode classic/gTb4b4b4, Ta5d6ff'classic'Tb4b4b4]Tb4b4b4,
Tb4b4b4[Ta5d6ff/microreticulum/gTb4b4b4, Ta5d6ff'uret'Tb4b4b4]Tb4b4b4,
Tb4b4b4[Ta5d6ff/rtnode/gTb4b4b4, Ta5d6ff'rtnode'Tb4b4b4]Tb4b4b4,
Tb4b4b4[Ta5d6ff/meshtastic/gTb4b4b4, Ta5d6ff'mt'Tb4b4b4]Tb4b4b4,
Tb4b4b4[Ta5d6ff/meshcore/gTb4b4b4, Ta5d6ff'mc'Tb4b4b4]Tb4b4b4,
Tb4b4b4[Ta5d6ff/companion/gTb4b4b4, Ta5d6ff'cmp'Tb4b4b4]Tb4b4b4,
Tb4b4b4[Ta5d6ff/repeater bridge/gTb4b4b4, Ta5d6ff'repbrg'Tb4b4b4]Tb4b4b4,
Tb4b4b4[Ta5d6ff/repeater/gTb4b4b4, Ta5d6ff'rep'Tb4b4b4]Tb4b4b4,
Tb4b4b4[Ta5d6ff/room server/gTb4b4b4, Ta5d6ff'room'Tb4b4b4]Tb4b4b4,
Tb4b4b4[Ta5d6ff/kiss modem/gTb4b4b4, Ta5d6ff'kiss'Tb4b4b4]Tb4b4b4,
Tb4b4b4[Ta5d6ff/merged binary/gTb4b4b4, Ta5d6ff'merged'Tb4b4b4]Tb4b4b4,
Tb4b4b4[Ta5d6ff/esp-now/gTb4b4b4, Ta5d6ff'espnow'Tb4b4b4]Tb4b4b4,
Tb4b4b4]Tb4b4b4;
Tff7b72function Te6edf3variantShortIdTb4b4b4(Te6edf3nameTb4b4b4) Tb4b4b4{
Tff7b72let Te6edf3s Tff7b72= Te6edf3nameTb4b4b4.Te6edf3toLowerCaseTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3s Tff7b72= Te6edf3sTb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/868\/915\/923/gTb4b4b4, Ta5d6ff'868'Tb4b4b4)Tb4b4b4; T8b949e// fixed tri-band idiom, never appears partially
Tff7b72for Tb4b4b4(Tff7b72const Tb4b4b4[Te6edf3reTb4b4b4, Te6edf3repTb4b4b4] Tff7b72of Te6edf3VARIANT_SLUG_ABBRTb4b4b4) Te6edf3s Tff7b72= Te6edf3sTb4b4b4.Te6edf3replaceTb4b4b4(Te6edf3reTb4b4b4, Te6edf3repTb4b4b4)Tb4b4b4;
Te6edf3s Tff7b72= Te6edf3sTb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/ghz/gTb4b4b4, Ta5d6ff'g'Tb4b4b4)Tb4b4b4;
Te6edf3s Tff7b72= Te6edf3sTb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/mhz/gTb4b4b4, Ta5d6ff''Tb4b4b4)Tb4b4b4;
Te6edf3s Tff7b72= Te6edf3sTb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/\./gTb4b4b4, Ta5d6ff''Tb4b4b4)Tb4b4b4;
Te6edf3s Tff7b72= Te6edf3sTb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/[^a-z0-9]+/gTb4b4b4, Ta5d6ff'-'Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3sTb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/^-+|-+$/gTb4b4b4, Ta5d6ff''Tb4b4b4)Tb4b4b4;
Tb4b4b4}

T8b949e// ══════════════════════════════════════════════════════════════
T8b949e// Hardware info database
T8b949e// ══════════════════════════════════════════════════════════════
Tff7b72const Te6edf3DEVICE_HW_INFO Tff7b72= Tb4b4b4{
Ta5d6ff'Heltec LoRa32 v2'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://heltec.org/project/wifi-lora-32v2/'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/heltec-v3.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'ΠšΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Π°Ρ ΠΏΠ»Π°Ρ‚Π° ESP32 с ΠΈΠ½Ρ‚Π΅Π³Ρ€ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΌ LoRa-ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΌ SX1276 ΠΈ OLED-дисплССм.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Compact ESP32 board with integrated SX1276 LoRa module and OLED display.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'8 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1276 / SX1278' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 20 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'0.96β€³ OLED' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'Micro-USB' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'Heltec LoRa32 v3'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://heltec.org/project/wifi-lora-32-v3/'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/heltec-v3.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'ΠžΠ±Π½ΠΎΠ²Π»Ρ‘Π½Π½Π°Ρ вСрсия Π½Π° ESP32-S3 с LoRa-Ρ‡ΠΈΠΏΠΎΠΌ SX1262 ΠΈ OLED. ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ WiFi, BLE ΠΈ LoRa ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Updated version on ESP32-S3 with SX1262 LoRa chip and OLED. Supports WiFi, BLE and LoRa simultaneously.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32-S3' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'8 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 22 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'0.96β€³ OLED' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'Heltec LoRa32 v4'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://heltec.org/project/wifi-lora-32-v4/'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/heltec_v4.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Ѐлагманская ΠΏΠ»Π°Ρ‚Π° Heltec Π½Π° ESP32-S3 с 16 ΠœΠ‘ Flash ΠΈ SX1262. УвСличСнная ΠΏΠ°ΠΌΡΡ‚ΡŒ, USB-C, OLED.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Heltec flagship board on ESP32-S3 with 16 MB Flash and SX1262. Extended memory, USB-C, OLED.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32-S3' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'16 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 28 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'0.96β€³ OLED' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'Heltec T114'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://heltec.org/project/mesh-node-t114/'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/heltec-mesh-node-t114.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Mesh-ΡƒΠ·Π΅Π» Π½Π° nRF52840 с SX1262 ΠΈ LCD-дисплССм. ΠŸΡ€Π΅Π΄Π½Π°Π·Π½Π°Ρ‡Π΅Π½ для носимых ΠΈ ΠΏΠΎΡ€Ρ‚Π°Ρ‚ΠΈΠ²Π½Ρ‹Ρ… ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠΉ.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Mesh node on nRF52840 with SX1262 and LCD display. Designed for wearable and portable use.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'nRF52840' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 22 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'1.14β€³ LCD (ST7789V2)' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'Heltec T096'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://heltec.org/project/t096/'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/heltec-t096.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'ΠšΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Ρ‹ΠΉ Ρ‚Ρ€Π΅ΠΊΠ΅Ρ€/ΡƒΠ·Π΅Π» Π½Π° nRF52840 с SX1262 ΠΈ LCD-дисплССм.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Compact tracker/node based on nRF52840 with SX1262 and LCD display.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'nRF52840' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 28 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'GPS'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'Integrated' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'0.96β€³ LCD (ST7735S)' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO LoRa32 v1.0'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://lilygo.cc/en-us/products/lora-v1-0-kit'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/tlora-v2-1-1_6.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Одна ΠΈΠ· ΠΏΠ΅Ρ€Π²Ρ‹Ρ… LoRa-ΠΏΠ»Π°Ρ‚ LilyGO Π½Π° ESP32 с SX1276 ΠΈ OLED. ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Ρ‡Π΅Ρ€Π΅Π· Micro-USB.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'One of the first LilyGO LoRa boards on ESP32 with SX1276 and OLED. Connects via Micro-USB.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1276 / SX1278' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 20 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'0.96β€³ OLED' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'Micro-USB' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO LoRa32 v2.0'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://lilygo.cc/en-us/products/lora-v1-3'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/tlora-v2-1-1_6.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'РСвизия v2.0 ΠΏΠ»Π°Ρ‚Ρ‹ LilyGO LoRa32 Π½Π° ESP32 с SX1276. ΠšΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Ρ‹ΠΉ Ρ„ΠΎΡ€ΠΌ-Ρ„Π°ΠΊΡ‚ΠΎΡ€ для ΠΏΠΎΡ€Ρ‚Π°Ρ‚ΠΈΠ²Π½Ρ‹Ρ… устройств.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Revision v2.0 of the LilyGO LoRa32 on ESP32 with SX1276. Compact form factor for portable devices.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1276 / SX1278' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 20 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'0.96β€³ OLED' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'Micro-USB' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO LoRa32 v2.1'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://lilygo.cc/en-us/products/lora3'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/tlora-v2-1-1_8.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'ΠΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Π°Ρ вСрсия LilyGO LoRa32 с USB-C ΠΈ SX1276. ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ΡΡ ΠΎΠΏΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ TCXO-Π²Π°Ρ€ΠΈΠ°Π½Ρ‚.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Current LilyGO LoRa32 version with USB-C and SX1276. Optional TCXO variant supported.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1276 / SX1278' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 20 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'0.96β€³ OLED' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T3S3'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://lilygo.cc/en-us/products/t3s3-v1-0'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/tlora-t3s3-v1.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'ΠœΠ½ΠΎΠ³ΠΎΡ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½Π°Ρ ESP32-S3 ΠΏΠ»Π°Ρ‚Π° с ΡˆΠΈΡ€ΠΎΠΊΠΈΠΌ Π²Ρ‹Π±ΠΎΡ€ΠΎΠΌ LoRa-Ρ‡ΠΈΠΏΠΎΠ²: SX127x, SX126x, SX1280.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Versatile ESP32-S3 board supporting a wide range of LoRa chips: SX127x, SX126x, SX1280.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32-S3' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX127x / SX126x / SX1280' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T-Beam'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://lilygo.cc/en-us/products/t-beam'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/tbeam.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'ΠšΠ»Π°ΡΡΠΈΡ‡Π΅ΡΠΊΠ°Ρ ESP32-ΠΏΠ»Π°Ρ‚Π° с GPS ΠΈ LoRa. Π‘Ρ‚Π°Π»Π° стандартом для LoRa-Ρ‚Ρ€Π΅ΠΊΠ΅Ρ€ΠΎΠ² ΠΈ mesh-ΡƒΠ·Π»ΠΎΠ².'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Classic ESP32 board with GPS and LoRa. Has become the standard for LoRa trackers and mesh nodes.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1276 / SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 22 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'GPS'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'NEO-6M / NEO-M8N' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'0.96β€³ OLED' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T-Beam Supreme'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://lilygo.cc/en-us/products/t-beam-supreme'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/tbeam-s3-core.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Π€Π»Π°Π³ΠΌΠ°Π½ T-Beam Π½Π° ESP32-S3 с SX1262, GPS, OLED ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Ρ‘Π½Π½ΠΎΠΉ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€ΠΎΠΉ питания.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'T-Beam flagship on ESP32-S3 with SX1262, GPS, OLED and updated power architecture.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32-S3' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 22 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'GPS'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'L76K' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'0.96β€³ OLED' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T-Beam Supreme V3'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://lilygo.cc/en-us/products/t-beam-supreme'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/tbeam-s3-core.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Π’Ρ€Π΅Ρ‚ΡŒΡ рСвизия T-Beam Supreme Π½Π° ESP32-S3 с SX1262. Π£Π»ΡƒΡ‡ΡˆΠ΅Π½Π½Ρ‹ΠΉ Π΄ΠΈΠ·Π°ΠΉΠ½ ΠΏΠ»Π°Ρ‚Ρ‹.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Third revision of T-Beam Supreme on ESP32-S3 with SX1262. Improved board design.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32-S3' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 22 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'GPS'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'Integrated' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'0.96β€³ OLED' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T-Deck'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://lilygo.cc/en-us/products/t-deck'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/t-deck.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'ΠœΠΈΠ½ΠΈΠ°Ρ‚ΡŽΡ€Π½ΠΎΠ΅ устройство с TFT-дисплССм 2.8β€³, ΠΊΠ»Π°Π²ΠΈΠ°Ρ‚ΡƒΡ€ΠΎΠΉ ΠΈ Ρ‚Ρ€Π΅ΠΊΠ±ΠΎΠ»ΠΎΠΌ. ESP32-S3 + SX1262.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Miniature device with 2.8β€³ TFT display, keyboard and trackball. ESP32-S3 + SX1262.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32-S3' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 22 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'2.8β€³ TFT' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Input'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'Keyboard + trackball' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'LilyGO T-Echo'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://lilygo.cc/en-us/products/t-echo'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/t-echo.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'ЭнСргоэффСктивный nRF52840-ΡƒΠ·Π΅Π» с SX1262, GPS ΠΈ e-paper-дисплССм. Π”ΠΎΠ»Π³ΠΎΠ΅ врСмя Π°Π²Ρ‚ΠΎΠ½ΠΎΠΌΠ½ΠΎΠΉ Ρ€Π°Π±ΠΎΡ‚Ρ‹.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Energy-efficient nRF52840 node with SX1262, GPS and e-paper display. Long battery life.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'nRF52840' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 22 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'GPS'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'L76K' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'1.54β€³ e-paper' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'Xiao ESP32S3'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://www.seeedstudio.com/XIAO-ESP32S3-p-5627.html'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/seeed-xiao-s3.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'ΠœΠΈΠ½ΠΈΠ°Ρ‚ΡŽΡ€Π½Π°Ρ ESP32-S3 ΠΏΠ»Π°Ρ‚Π° ΠΎΡ‚ Seeed. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ с внСшним LoRa-ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΌ Π½Π° SX126x ΠΈΠ»ΠΈ SX127x.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Miniature ESP32-S3 board from Seeed. Used with an external LoRa module on SX126x or SX127x.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32-S3' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'External module' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'RAK4631'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://docs.rakwireless.com/product-categories/wisblock/rak4631/overview/'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/rak4631.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'WisBlock Core-ΠΌΠΎΠ΄ΡƒΠ»ΡŒ Π½Π° nRF52840 ΠΈ SX1262 ΠΎΡ‚ RAKwireless. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π² экосистСмС WisBlock.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'WisBlock Core module based on nRF52840 and SX1262 from RAKwireless. Used within the WisBlock ecosystem.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'nRF52840' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 22 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Form'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'WisBlock module' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'SenseCAP T1000E'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://www.seeedstudio.com/SenseCAP-Card-Tracker-T1000-E-for-Meshtastic-p-5913.html'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/tracker-t1000-e.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Π’Ρ€Π΅ΠΊΠ΅Ρ€ Π² Ρ„ΠΎΡ€ΠΌ-Ρ„Π°ΠΊΡ‚ΠΎΡ€Π΅ ΠΊΡ€Π΅Π΄ΠΈΡ‚Π½ΠΎΠΉ ΠΊΠ°Ρ€Ρ‚Ρ‹ Π½Π° nRF52840 + SX1262 + GPS. ΠšΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Ρ‹ΠΉ ΠΈ Π΄ΠΎΠ»Π³ΠΎΠΆΠΈΠ²ΡƒΡ‰ΠΈΠΉ.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'Credit-card form factor tracker with nRF52840, SX1262 and GPS. Compact and long-lived.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'nRF52840' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 22 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'GPS'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'Integrated' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Form'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'Credit card' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'MeshAdventurer-S3'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://git.rns.moscow/deuxyeux/MeshAdventurer-S3'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/meshadventurer-s3.png'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Высокомощный ΡƒΠ·Π΅Π» Π½Π° ESP32-S3 с ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΌ Ebyte E22-900M30S для стационарного ΠΈ мобильного примСнСния.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'High-power node on ESP32-S3 with Ebyte E22-900M30S module for stationary and mobile use.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32-S3' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'16 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262 (E22-900M30S)' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 30 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'MeshPoE-S3'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://git.rns.moscow/deuxyeux/MeshPoE-S3'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/meshpoe-s3.png'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Π£Π½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½Ρ‹ΠΉ LoRa-ΡƒΠ·Π΅Π» с ΠΏΡ€ΠΎΠ²ΠΎΠ΄Π½Ρ‹ΠΌ Ethernet ΠΈ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ PoE для стационарного использования.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'A universal LoRa node with wired Ethernet and PoE support designed for stationary use.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32-S3' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'16 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262 (E22P-868M30S)' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 30 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'PoE + USB-C' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'Aethernode-S3'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://github.com/ahedproductions/aethernodeS3'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/aethernode-s3.png'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Высокомощный стационарный LoRa-ΡƒΠ·Π΅Π» Π½Π° ESP32-S3 с ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΌ Ebyte E22-400M33S (SX1268) ΠΈ 16 ΠœΠ‘ Flash.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'High-power stationary LoRa node on ESP32-S3 with Ebyte E22-400M33S module (SX1268) and 16 MB Flash.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32-S3' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'16 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1268 (E22-400M33S)' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 33 dBm' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'Aethernode'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://github.com/ahedproductions/aethernode'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/aethernode.png'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Высокомощный стационарный LoRa-ΡƒΠ·Π΅Π» Π½Π° ESP32 с ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΌ Ebyte E22-400M33S (SX1268).'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'High-power stationary LoRa node on ESP32 with Ebyte E22-400M33S module (SX1268).' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1268 (E22-400M33S)' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 33 dBm' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'MeshAdventurer'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://github.com/chrismyers2000/MeshAdventurer'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/meshadventurer.png'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Высокомощный ΡƒΠ·Π΅Π» Π½Π° ESP32 с ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΌ Ebyte E22-900M30S для стационарного ΠΈ мобильного примСнСния.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'High-power node on ESP32 with Ebyte E22-900M30S module for stationary and mobile use.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262 (E22-900M30S)' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 30 dBm' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'DIY-V1'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://github.com/NanoVHF/Meshtastic-DIY'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/diy.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'DIY-конструкция Π½Π° ESP32 с ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… LoRa-ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ. ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚Π°Ρ схСма, доступная для ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ сборки.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'DIY build on ESP32 supporting various LoRa modules. Open schematic available for self-assembly.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'Various modules' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'FakeTec (Promicro/nice!nano)'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://github.com/gargomoma/fakeTec_pcb'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/promicro.svg'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'DIY-ΡƒΠ·Π΅Π» Π½Π° nRF52840 Π½Π° Π±Π°Π·Π΅ ProMicro ΠΈΠ»ΠΈ nice!nano. ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚Π°Ρ PCB ΠΎΡ‚ сообщСства.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'DIY nRF52840 node using ProMicro or nice!nano boards. Open-source PCB from the community.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'nRF52840' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 22 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Base'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ProMicro / nice!nano' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'Aethermobi'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://github.com/ahedproductions/aethermobi'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/aethermobi.png'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'FakeTec-совмСстимый ΠΏΠΎΡ€Ρ‚Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ ΡƒΠ·Π΅Π» Π½Π° аккумуляторС ΠΎΡ‚ Aetherlab Π½Π° Π±Π°Π·Π΅ nRF52840.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'FakeTec-compatible portable battery-powered nRF52840 node by Aetherlab.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'nRF52840' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1262 (E22-400M30S)' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 30 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Battery'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'2Γ—18650' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff'RNode NG (v2.0 / v2.1)'Tff7b72: Tb4b4b4{
Te6edf3urlTff7b72: Ta5d6ff'https://unsigned.io/hardware/RNode.html'Tb4b4b4,
Te6edf3imageTff7b72: Ta5d6ff'img/devices/rnode.png'Tb4b4b4,
Te6edf3descTff7b72: Tb4b4b4{ Te6edf3ruTff7b72: Ta5d6ff'Π’Ρ‚ΠΎΡ€ΠΎΠ΅ ΠΏΠΎΠΊΠΎΠ»Π΅Π½ΠΈΠ΅ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ Π΄ΠΈΠ·Π°ΠΉΠ½Π° RNode ΠΎΡ‚ ΠœΠ°Ρ€ΠΊΠ° ΠšΠ²ΠΈΡΡ‚Π°. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΏΠ»Π°Ρ‚Ρƒ LilyGO LoRa32 v2.1.'Tb4b4b4, Te6edf3enTff7b72: Ta5d6ff'The second iteration of Mark Qvist\'s original RNode design, built on a LilyGO LoRa32 v2.1.' Tb4b4b4}Tb4b4b4,
Te6edf3specsTff7b72: Tb4b4b4[Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'MCU'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'ESP32' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Flash'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'4 MB' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'LoRa'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'SX1276 / SX1278' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'TX Power'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'up to 20 dBm' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'Display'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'OLED' Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3keyTff7b72: Ta5d6ff'USB'Tb4b4b4, Te6edf3valTff7b72: Ta5d6ff'Micro-USB' Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4;

T8b949e// ══════════════════════════════════════════════════════════════
T8b949e// Vue App
T8b949e// ══════════════════════════════════════════════════════════════
Te6edf3VueTb4b4b4.Te6edf3createAppTb4b4b4(Tb4b4b4{
Te6edf3dataTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{
Te6edf3langTff7b72: Tb4b4b4(Tff7b72functionTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72var Te6edf3alt Tff7b72= Tffa657windowTb4b4b4.Te6edf3BRANDSTb4b4b4[Tffa657windowTb4b4b4.Te6edf3BRAND_IDTb4b4b4]Tb4b4b4.Te6edf3altLangTb4b4b4;
Tff7b72var Te6edf3saved Tff7b72= Te6edf3localStorageTb4b4b4.Te6edf3getItemTb4b4b4(Ta5d6ff'lang'Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3saved Tff7b72=== Te6edf3alt Tff7b72|| Te6edf3saved Tff7b72=== Ta5d6ff'en'Tb4b4b4) Tff7b72return Te6edf3savedTb4b4b4;
Tff7b72var Te6edf3nav Tff7b72= Tb4b4b4(Te6edf3navigatorTb4b4b4.Te6edf3languages Tff7b72&& Te6edf3navigatorTb4b4b4.Te6edf3languagesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4) Tff7b72|| Te6edf3navigatorTb4b4b4.Te6edf3language Tff7b72|| Ta5d6ff''Tb4b4b4;
Tff7b72return Te6edf3navTb4b4b4.Te6edf3toLowerCaseTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3startsWithTb4b4b4(Te6edf3altTb4b4b4) Tff7b72? Te6edf3alt Tff7b72: Ta5d6ff'en'Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3themeTff7b72: Ta5d6ff'dark'Tb4b4b4,
Te6edf3brandIdTff7b72: Tffa657windowTb4b4b4.Te6edf3BRAND_IDTb4b4b4,
Te6edf3brandTff7b72: Tffa657windowTb4b4b4.Te6edf3BRANDSTb4b4b4[Tffa657windowTb4b4b4.Te6edf3BRAND_IDTb4b4b4]Tb4b4b4,

Te6edf3deviceGroupsTff7b72: Te6edf3DEVICE_GROUPSTb4b4b4,
Te6edf3selectedDeviceTff7b72: Tff7b72nullTb4b4b4,
Te6edf3selectedVariantTff7b72: Tff7b72nullTb4b4b4,

Te6edf3isWorkingTff7b72: Tff7b72falseTb4b4b4,
Te6edf3flashProgressTff7b72: T79c0ff0Tb4b4b4,
Te6edf3currentStepTff7b72: Ta5d6ff''Tb4b4b4,
Te6edf3statusTypeTff7b72: Ta5d6ff''Tb4b4b4,
Te6edf3statusMsgTff7b72: Ta5d6ff''Tb4b4b4,
Te6edf3showAdvancedTff7b72: Tff7b72falseTb4b4b4,
Te6edf3showOtherFirmwaresTff7b72: Tff7b72falseTb4b4b4,
Te6edf3scrolledTff7b72: Tff7b72falseTb4b4b4,

T8b949e// Baud rate that last completed an esptool handshake on this
T8b949e// machine+board. espConnect() starts from it so a board that needed
T8b949e// to fall back once doesn't pay for the failed attempt again.
Te6edf3espBaudrateTff7b72: Tff7b72nullTb4b4b4,

Te6edf3logTff7b72: Tb4b4b4[Tb4b4b4]Tb4b4b4,
Te6edf3progressLineIdxTff7b72: Tff7b72-T79c0ff1Tb4b4b4,
Te6edf3screenImageTff7b72: Tff7b72nullTb4b4b4,
Te6edf3autoRefreshTff7b72: Tff7b72falseTb4b4b4,
Te6edf3isReconditioningTff7b72: Tff7b72falseTb4b4b4,

T8b949e// Node configuration tabs
Te6edf3cfgTabTff7b72: Ta5d6ff'info'Tb4b4b4,
Te6edf3connectedPortTff7b72: Tff7b72nullTb4b4b4,
Te6edf3connectedNetworkUrlTff7b72: Tff7b72nullTb4b4b4,
Te6edf3networkHostTff7b72: Ta5d6ff''Tb4b4b4,
Te6edf3bootloaderWarnedTff7b72: Tff7b72falseTb4b4b4,
Te6edf3connectedDeviceTff7b72: Ta5d6ff''Tb4b4b4,
Te6edf3connectedFwVerTff7b72: Ta5d6ff''Tb4b4b4,
Te6edf3connectedPlatformTff7b72: Tff7b72nullTb4b4b4,
Te6edf3detectedChipTff7b72: Tff7b72nullTb4b4b4,
Te6edf3detectedChipDescTff7b72: Tff7b72nullTb4b4b4,
Te6edf3detectedFlashTff7b72: Tff7b72nullTb4b4b4,

Te6edf3tncEnabledTff7b72: Tff7b72nullTb4b4b4,
Te6edf3radioFreqMhzTff7b72: Ta5d6ff'868.825'Tb4b4b4, Te6edf3radioBwHzTff7b72: T79c0ff125000Tb4b4b4, Te6edf3radioTxPowerTff7b72: T79c0ff17Tb4b4b4, Te6edf3radioSfTff7b72: T79c0ff10Tb4b4b4, Te6edf3radioCrTff7b72: T79c0ff7Tb4b4b4,
Te6edf3dispRotationTff7b72: T79c0ff0Tb4b4b4, Te6edf3dispIntensityTff7b72: T79c0ff255Tb4b4b4, Te6edf3dispTimeoutTff7b72: T79c0ff0Tb4b4b4,
Te6edf3wifiModeTff7b72: T79c0ff0Tb4b4b4, Te6edf3wifiSsidTff7b72: Ta5d6ff''Tb4b4b4, Te6edf3wifiPskTff7b72: Ta5d6ff''Tb4b4b4, Te6edf3wifiChannelTff7b72: T79c0ff1Tb4b4b4,
Te6edf3wifiIpTff7b72: Ta5d6ff''Tb4b4b4, Te6edf3wifiNmTff7b72: Ta5d6ff''Tb4b4b4, Te6edf3wifiGwTff7b72: Ta5d6ff''Tb4b4b4, Te6edf3wifiDnsTff7b72: Ta5d6ff''Tb4b4b4,
Te6edf3ethSpeedTff7b72: T79c0ff0Tb4b4b4, Te6edf3ethIpTff7b72: Ta5d6ff''Tb4b4b4, Te6edf3ethNmTff7b72: Ta5d6ff''Tb4b4b4, Te6edf3ethGwTff7b72: Ta5d6ff''Tb4b4b4, Te6edf3ethDnsTff7b72: Ta5d6ff''Tb4b4b4,
Te6edf3btEnabledTff7b72: Tff7b72falseTb4b4b4, Te6edf3btPinTff7b72: Ta5d6ff''Tb4b4b4, Te6edf3btPairingTff7b72: Tff7b72falseTb4b4b4,
Te6edf3sndEnabledTff7b72: Tff7b72nullTb4b4b4,
Te6edf3vsenseDividerTff7b72: T79c0ff11.0Tb4b4b4,
Te6edf3rtcTimeTff7b72: T79c0ff0Tb4b4b4,

Te6edf3hasSerialTff7b72: Tff7b72!Tff7b72!Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4,
T8b949e// true on https:// (and http://localhost) - false on a plain-http
T8b949e// origin like ws.rns.moscow. USB flashing needs Web Serial, which
T8b949e// browsers only expose in a secure context, so it's gated on this;
T8b949e// "connect via network" is gated on the opposite, since it needs a
T8b949e// non-secure origin to open ws:// without the mixed-content block.
Te6edf3isSecureContextTff7b72: Tffa657windowTb4b4b4.Te6edf3isSecureContextTb4b4b4,
T8b949e// Drives the small transport dropdown next to the Connect button.
T8b949e// Defaults to whichever transport this origin actually supports;
T8b949e// picking the other one hands off to the sibling site (see
T8b949e// onTransportChange), since a single page load can't do both.
Te6edf3transportChoiceTff7b72: Tffa657windowTb4b4b4.Te6edf3isSecureContext Tff7b72? Ta5d6ff'usb' Tff7b72: Ta5d6ff'ws'Tb4b4b4,
Te6edf3firmwareVersionsTff7b72: Tb4b4b4{Tb4b4b4}Tb4b4b4,
Te6edf3linkCopiedTff7b72: Tff7b72falseTb4b4b4,
Te6edf3uf2ExistsTff7b72: Tff7b72falseTb4b4b4,
Tb4b4b4}Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3computedTff7b72: Tb4b4b4{
Te6edf3canFlashTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72!Tff7b72!Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3selectedDevice Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3hasSerialTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
T8b949e// Node configuration (withRNode()) works over either transport, unlike
T8b949e// flashing, which stays serial-only.
Te6edf3hasLiveConnectionTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72!Tff7b72!Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedPort Tff7b72|| Tff7b72thisTb4b4b4.Te6edf3connectedNetworkUrlTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3hwInfoTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72thisTb4b4b4.Te6edf3selectedDevice Tff7b72? Tb4b4b4(Te6edf3DEVICE_HW_INFOTb4b4b4[Tff7b72thisTb4b4b4.Te6edf3selectedDeviceTb4b4b4.Te6edf3nameTb4b4b4] Tff7b72|| Tff7b72nullTb4b4b4) Tff7b72: Tff7b72nullTb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3selectedFirmwareInfoTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3selectedVariantTb4b4b4) Tff7b72return Tff7b72nullTb4b4b4;
Tff7b72return Tff7b72thisTb4b4b4.Te6edf3firmwareVersionsTb4b4b4[Tff7b72thisTb4b4b4.Te6edf3selectedVariantTb4b4b4.Te6edf3firmware_zipTb4b4b4] Tff7b72|| Tff7b72nullTb4b4b4;
Tb4b4b4}Tb4b4b4,
T8b949e// Both only meaningful once a connected board has been resolved to one
T8b949e// exact variant (see the productId === 0xF0 "Homebrew" case in
T8b949e// detectDevice/detectDeviceOverNetwork, where selectedVariant is
T8b949e// deliberately left null - up to 8 different boards share that product
T8b949e// id, so there's no single "latest" version to compare against).
Te6edf3firmwareUpdateAvailableTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72!Tff7b72!Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedFwVer Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3selectedFirmwareInfo Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3selectedFirmwareInfoTb4b4b4.Te6edf3version Tff7b72!== Tff7b72thisTb4b4b4.Te6edf3connectedFwVerTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3firmwareUpToDateTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72!Tff7b72!Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedFwVer Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3selectedFirmwareInfo Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3selectedFirmwareInfoTb4b4b4.Te6edf3version Tff7b72=== Tff7b72thisTb4b4b4.Te6edf3connectedFwVerTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
T8b949e// Overrides the "Detected: <name>" status badge once we know whether
T8b949e// the connected board's firmware is current - the device/platform
T8b949e// badges next to Connect already show what was detected, so repeating
T8b949e// the name here would be redundant once we have something more useful
T8b949e// to say about it.
Te6edf3detectedStatusTextTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3statusMsgTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'Detected: 'Tb4b4b4)Tb4b4b4) Tff7b72return Tff7b72thisTb4b4b4.Te6edf3statusMsgTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3firmwareUpdateAvailableTb4b4b4) Tff7b72return Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.update_available'Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3firmwareUpToDateTb4b4b4) Tff7b72return Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.up_to_date'Tb4b4b4)Tb4b4b4;
Tff7b72return Tff7b72thisTb4b4b4.Te6edf3statusMsgTb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3detectedStatusClassTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3statusMsgTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'Detected: 'Tb4b4b4)Tb4b4b4) Tff7b72return Tff7b72thisTb4b4b4.Te6edf3statusTypeTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3firmwareUpdateAvailableTb4b4b4) Tff7b72return Ta5d6ff'warn'Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3firmwareUpToDateTb4b4b4) Tff7b72return Ta5d6ff'success'Tb4b4b4;
Tff7b72return Tff7b72thisTb4b4b4.Te6edf3statusTypeTb4b4b4;
Tb4b4b4}Tb4b4b4,
T8b949e// UF2 images (for nRF52 boards' Adafruit bootloader) are built as an
T8b949e// optional sibling of the .zip, same directory, same name β€” presence
T8b949e// isn't known ahead of time, so uf2Exists is checked live (see watch).
Te6edf3uf2UrlTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72|| Tff7b72thisTb4b4b4.Te6edf3selectedVariantTb4b4b4.Te6edf3platform Tff7b72!== Ta5d6ff'nrf52'Tb4b4b4) Tff7b72return Tff7b72nullTb4b4b4;
Tff7b72return Tff7b72thisTb4b4b4.Te6edf3selectedVariantTb4b4b4.Te6edf3firmware_zipTb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/\.zip$/Tb4b4b4, Ta5d6ff'.uf2'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3connectedPlatformLabelTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4) Tff7b72return Ta5d6ff''Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3PLATFORM_ESP32Tb4b4b4) Tff7b72return Ta5d6ff'ESP32'Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3PLATFORM_NRF52Tb4b4b4) Tff7b72return Ta5d6ff'nRF52'Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3PLATFORM_AVRTb4b4b4) Tff7b72return Ta5d6ff'AVR'Tb4b4b4;
T8b949e// Platform query hasn't resolved yet (or timed out) - same
T8b949e// DEVICE_HARDWARE fallback wifiSupported() below uses.
Tff7b72const Te6edf3hw Tff7b72= Te6edf3DEVICE_HARDWARETb4b4b4[Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4]Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3hwTff7b72?Tb4b4b4.Te6edf3chipTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'ESP32'Tb4b4b4)Tb4b4b4) Tff7b72return Ta5d6ff'ESP32'Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3hwTff7b72?Tb4b4b4.Te6edf3chipTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'nRF52'Tb4b4b4)Tb4b4b4) Tff7b72return Ta5d6ff'nRF52'Tb4b4b4;
Tff7b72return Ta5d6ff''Tb4b4b4;
Tb4b4b4}Tb4b4b4,
T8b949e// Gates the "Enter DFU Mode" advanced tool: only meaningful for nRF52
T8b949e// boards, whether identified by the currently selected firmware variant
T8b949e// (device not connected yet) or by an already-connected/detected device.
Te6edf3nrf52RelevantTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3selectedVariantTff7b72?Tb4b4b4.Te6edf3platform Tff7b72=== Ta5d6ff'nrf52'Tb4b4b4) Tff7b72return Tff7b72trueTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3PLATFORM_NRF52Tb4b4b4) Tff7b72return Tff7b72trueTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3detectedChip Tff7b72=== Ta5d6ff'nRF52'Tb4b4b4) Tff7b72return Tff7b72trueTb4b4b4;
Tff7b72const Te6edf3hw Tff7b72= Tff7b72thisTb4b4b4.Te6edf3selectedDevice Tff7b72? Te6edf3DEVICE_HARDWARETb4b4b4[Tff7b72thisTb4b4b4.Te6edf3selectedDeviceTb4b4b4.Te6edf3nameTb4b4b4] Tff7b72: Tff7b72nullTb4b4b4;
Tff7b72return Tff7b72!Tff7b72!Te6edf3hw Tff7b72&& Te6edf3hwTb4b4b4.Te6edf3chipTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'nRF52'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3wifiSupportedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4) Tff7b72return Tff7b72falseTb4b4b4;
T8b949e// Platform byte reported by the RNode firmware is authoritative
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72!== Tff7b72nullTb4b4b4) Tff7b72return Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3PLATFORM_ESP32Tb4b4b4;
Tff7b72const Te6edf3hw Tff7b72= Te6edf3DEVICE_HARDWARETb4b4b4[Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4]Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3hwTb4b4b4) Tff7b72return Te6edf3hwTb4b4b4.Te6edf3chipTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'ESP32'Tb4b4b4)Tb4b4b4;
Tff7b72return Tff7b72trueTb4b4b4;
Tb4b4b4}Tb4b4b4,
T8b949e// Every ESP32 variant has WiFi built in, so unlike Ethernet there's no
T8b949e// "right platform, wrong board" case worth explaining with a tooltip β€”
T8b949e// non-ESP32 (nRF52, AVR) just fully hides the tab, same as ethernetHidden.
Te6edf3wifiHiddenTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4) Tff7b72return Tff7b72falseTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72!== Tff7b72nullTb4b4b4) Tff7b72return Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72!== Te6edf3ROMTb4b4b4.Te6edf3PLATFORM_ESP32Tb4b4b4;
Tff7b72const Te6edf3hw Tff7b72= Te6edf3DEVICE_HARDWARETb4b4b4[Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4]Tb4b4b4;
Tff7b72return Tff7b72!Tff7b72!Te6edf3hw Tff7b72&& Tff7b72!Te6edf3hwTb4b4b4.Te6edf3chipTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'ESP32'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3ethernetSupportedTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Wired Ethernet (W5500) only exists on MeshPoE-S3 hardware, but
T8b949e// product 0xF0 (all homebrew PCBs) collapses to 'Homebrew' on
T8b949e// connect since model_id doesn't disambiguate the specific board β€”
T8b949e// same imprecision miscSupported already accepts below.
Tff7b72return Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72=== Ta5d6ff'Homebrew'Tb4b4b4;
Tb4b4b4}Tb4b4b4,
T8b949e// nRF52 boards have no Ethernet MAC/PHY pins at all, so unlike the
T8b949e// ESP32-only-but-wrong-board case above (still shown, just disabled β€”
T8b949e// see tab.ethernet.unsupported), there's nothing to explain: the tab
T8b949e// is fully hidden rather than shown-disabled.
Te6edf3ethernetHiddenTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4) Tff7b72return Tff7b72falseTb4b4b4;
T8b949e// Platform byte reported by the RNode firmware is authoritative β€”
T8b949e// same precedence as wifiSupported() above. Falls back to the
T8b949e// DEVICE_HARDWARE name guess only if that hasn't resolved yet.
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72!== Tff7b72nullTb4b4b4) Tff7b72return Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3PLATFORM_NRF52Tb4b4b4;
Tff7b72const Te6edf3hw Tff7b72= Te6edf3DEVICE_HARDWARETb4b4b4[Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4]Tb4b4b4;
Tff7b72return Tff7b72!Tff7b72!Te6edf3hw Tff7b72&& Te6edf3hwTb4b4b4.Te6edf3chipTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'nRF52'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3miscSupportedTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Custom options only exist in our homebrew firmware builds
T8b949e// (e.g. MeshAdventurer-S3), identified by product ID 0xF0
Tff7b72return Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72=== Ta5d6ff'Homebrew'Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3rtcTimeDisplayTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// 0 = no RTC chip present/readable; anything before ~2020 is not a
T8b949e// real synced timestamp either (DS3231 default/erased state), so
T8b949e// both read as "not set" rather than a bogus 1970s date.
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3rtcTime Tff7b72|| Tff7b72thisTb4b4b4.Te6edf3rtcTime Tff7b72< T79c0ff1577836800Tb4b4b4) Tff7b72return Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'misc.rtc.unavailable'Tb4b4b4)Tb4b4b4;
Tff7b72return Tff7b72new Tffa657DateTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3rtcTime Tff7b72* T79c0ff1000Tb4b4b4)Tb4b4b4.Te6edf3toISOStringTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff'T'Tb4b4b4, Ta5d6ff' 'Tb4b4b4)Tb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff'.000Z'Tb4b4b4, Ta5d6ff' UTC'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3oledDisplayTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Boards with a real backlit/frontlit LCD have a genuinely useful
T8b949e// continuous brightness range; everything else is an OLED whose
T8b949e// contrast register only really supports off/dim/bright (confirmed
T8b949e// on MeshAdventurer-S3 hardware - the intensity byte still gets
T8b949e// stored/sent as-is, just picked from 3 fixed values instead of a
T8b949e// slider). All "Homebrew RNode" boards (shared product ID 0xF0) are
T8b949e// OLED today; update this list if that ever changes.
Tff7b72const Te6edf3lcdDevices Tff7b72= Tb4b4b4[Ta5d6ff'Heltec T114'Tb4b4b4, Ta5d6ff'Heltec T096'Tb4b4b4, Ta5d6ff'LilyGO T-Echo'Tb4b4b4]Tb4b4b4;
Tff7b72return Tff7b72!Te6edf3lcdDevicesTb4b4b4.Te6edf3includesTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3visibleVariantsTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3selectedDeviceTb4b4b4) Tff7b72return Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3vars Tff7b72= Tff7b72thisTb4b4b4.Te6edf3selectedDeviceTb4b4b4.Te6edf3variantsTb4b4b4;
Tff7b72return Te6edf3varsTb4b4b4.Te6edf3filterTb4b4b4(Te6edf3v Tb4b4b4=> Tff7b72thisTb4b4b4.Te6edf3isNonReticulumTb4b4b4(Te6edf3vTb4b4b4) Tff7b72=== Tff7b72thisTb4b4b4.Te6edf3showOtherFirmwaresTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
T8b949e// Already-flashed boards skip esptool chip detection entirely (RNode
T8b949e// firmware answers directly), so detectedChip/detectedFlash never get
T8b949e// set for them - but a connected-yet-unresolved board (the ambiguous
T8b949e// "Homebrew" product id, shared by both ESP32- and nRF52-family boards -
T8b949e// see productId === 0xF0 in detectDevice/detectDeviceOverNetwork) still
T8b949e// reports its platform family via getPlatform(). Use that to narrow the
T8b949e// list the same way, family-level only (ESP32 vs ESP32-S3 isn't
T8b949e// distinguishable this way).
Te6edf3detectedPlatformFamilyTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3detectedChip Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3selectedDeviceTb4b4b4)
Tff7b72? Tff7b72thisTb4b4b4.Te6edf3connectedPlatformLabel
Tff7b72: Ta5d6ff''Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3filteredDeviceGroupsTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3chip Tff7b72= Tff7b72thisTb4b4b4.Te6edf3detectedChipTb4b4b4;
Tff7b72const Te6edf3flash Tff7b72= Tff7b72thisTb4b4b4.Te6edf3detectedFlashTb4b4b4;
Tff7b72const Te6edf3family Tff7b72= Tff7b72thisTb4b4b4.Te6edf3detectedPlatformFamilyTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3chip Tff7b72&& Tff7b72!Te6edf3flash Tff7b72&& Tff7b72!Te6edf3familyTb4b4b4) Tff7b72return Tff7b72thisTb4b4b4.Te6edf3deviceGroupsTb4b4b4;
Tff7b72return Tff7b72thisTb4b4b4.Te6edf3deviceGroups
Tb4b4b4.Te6edf3mapTb4b4b4(Te6edf3grp Tb4b4b4=> Tb4b4b4(Tb4b4b4{
Tb4b4b4...Te6edf3grpTb4b4b4,
Te6edf3devicesTff7b72: Te6edf3grpTb4b4b4.Te6edf3devicesTb4b4b4.Te6edf3filterTb4b4b4(Te6edf3d Tb4b4b4=> Tb4b4b4{
Tff7b72const Te6edf3hw Tff7b72= Te6edf3DEVICE_HARDWARETb4b4b4[Te6edf3dTb4b4b4.Te6edf3nameTb4b4b4]Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3hwTb4b4b4) Tff7b72return Tff7b72falseTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3chip Tff7b72&& Te6edf3hwTb4b4b4.Te6edf3chip Tff7b72!== Te6edf3chipTb4b4b4) Tff7b72return Tff7b72falseTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3flash Tff7b72&& Te6edf3hwTb4b4b4.Te6edf3flash Tff7b72!== Te6edf3flashTb4b4b4) Tff7b72return Tff7b72falseTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3family Tff7b72&& Tff7b72!Te6edf3hwTb4b4b4.Te6edf3chipTb4b4b4.Te6edf3startsWithTb4b4b4(Te6edf3familyTb4b4b4)Tb4b4b4) Tff7b72return Tff7b72falseTb4b4b4;
Tff7b72return Tff7b72trueTb4b4b4;
Tb4b4b4}Tb4b4b4)
Tb4b4b4}Tb4b4b4)Tb4b4b4)
Tb4b4b4.Te6edf3filterTb4b4b4(Te6edf3grp Tb4b4b4=> Te6edf3grpTb4b4b4.Te6edf3devicesTb4b4b4.Te6edf3length Tff7b72> T79c0ff0Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3mountedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tffa657windowTb4b4b4.Te6edf3addEventListenerTb4b4b4(Ta5d6ff'scroll'Tb4b4b4, Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3scrolled Tff7b72= Tffa657windowTb4b4b4.Te6edf3scrollY Tff7b72> T79c0ff16Tb4b4b4;
Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3passiveTff7b72: Tff7b72true Tb4b4b4}Tb4b4b4)Tb4b4b4;

T8b949e// Picking "WS"/"USB" in the transport dropdown navigates away to the
T8b949e// sibling site. If the user then hits Back, bfcache can restore this
T8b949e// page exactly as it was at that moment - dropdown still showing the
T8b949e// choice that was about to navigate away, even though Connect (unrelated
T8b949e// to transportChoice) will still act on this page's own transport. Reset
T8b949e// it back to this origin's real default whenever the page is restored
T8b949e// from bfcache.
Tffa657windowTb4b4b4.Te6edf3addEventListenerTb4b4b4(Ta5d6ff'pageshow'Tb4b4b4, Tb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3eTb4b4b4.Te6edf3persistedTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3transportChoice Tff7b72= Tff7b72thisTb4b4b4.Te6edf3isSecureContext Tff7b72? Ta5d6ff'usb' Tff7b72: Ta5d6ff'ws'Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;

Tffa657windowTb4b4b4.Te6edf3setLangTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3langTb4b4b4)Tb4b4b4;

Tff7b72const Te6edf3saved Tff7b72= Te6edf3localStorageTb4b4b4.Te6edf3getItemTb4b4b4(Ta5d6ff'theme'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3preferred Tff7b72= Te6edf3saved Tff7b72|| Tb4b4b4(Tffa657windowTb4b4b4.Te6edf3matchMediaTb4b4b4(Ta5d6ff'(prefers-color-scheme: light)'Tb4b4b4)Tb4b4b4.Te6edf3matches Tff7b72? Ta5d6ff'light' Tff7b72: Ta5d6ff'dark'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3applyThemeTb4b4b4(Te6edf3preferredTb4b4b4)Tb4b4b4;

Tff7b72if Tb4b4b4(Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4) Tb4b4b4{
Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4.Te6edf3getPortsTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3thenTb4b4b4(Te6edf3ports Tb4b4b4=> Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3portsTb4b4b4.Te6edf3length Tff7b72=== T79c0ff1Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3connectedPort Tff7b72= Te6edf3portsTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4.Tff7b72catchTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}

Te6edf3fetchTb4b4b4(Ta5d6ff'/firmware/versions.json'Tb4b4b4)
Tb4b4b4.Te6edf3thenTb4b4b4(Te6edf3r Tb4b4b4=> Te6edf3rTb4b4b4.Te6edf3jsonTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4.Te6edf3thenTb4b4b4(Te6edf3d Tb4b4b4=> Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3firmwareVersions Tff7b72= Te6edf3dTb4b4b4; Tb4b4b4}Tb4b4b4)
Tb4b4b4.Tff7b72catchTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{Tb4b4b4}Tb4b4b4)Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3applyDirectLinkTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3watchTff7b72: Tb4b4b4{
Te6edf3showOtherFirmwaresTb4b4b4(Te6edf3valTb4b4b4) Tb4b4b4{
T8b949e// Clear the selection if it's no longer in the visible set after toggling
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3isNonReticulumTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3selectedVariantTb4b4b4) Tff7b72!== Te6edf3valTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72= Tff7b72nullTb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
T8b949e// Only one variant to pick from - no need to make the user click the
T8b949e// dropdown just to choose the sole option (fires on device selection,
T8b949e// auto-detect, and the "other firmwares" toggle alike since all three
T8b949e// route through this computed).
Te6edf3visibleVariantsTb4b4b4(Te6edf3varsTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3varsTb4b4b4.Te6edf3length Tff7b72=== T79c0ff1 Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3selectedVariantTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72= Te6edf3varsTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3uf2UrlTff7b72: Tb4b4b4{
Te6edf3immediateTff7b72: Tff7b72trueTb4b4b4,
Te6edf3handlerTb4b4b4(Te6edf3urlTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3uf2Exists Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3urlTb4b4b4) Tff7b72returnTb4b4b4;
Te6edf3fetchTb4b4b4(Te6edf3urlTb4b4b4, Tb4b4b4{ Te6edf3methodTff7b72: Ta5d6ff'HEAD'Tb4b4b4, Te6edf3cacheTff7b72: Ta5d6ff'no-store' Tb4b4b4}Tb4b4b4)
Tb4b4b4.Te6edf3thenTb4b4b4(Te6edf3r Tb4b4b4=> Tb4b4b4{ Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3uf2Url Tff7b72=== Te6edf3urlTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3uf2Exists Tff7b72= Te6edf3rTb4b4b4.Te6edf3okTb4b4b4; Tb4b4b4}Tb4b4b4)
Tb4b4b4.Tff7b72catchTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3logTff7b72: Tb4b4b4{
Te6edf3deepTff7b72: Tff7b72trueTb4b4b4,
Te6edf3handlerTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3$nextTickTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72const Te6edf3el Tff7b72= Tff7b72thisTb4b4b4.Te6edf3$refsTb4b4b4.Te6edf3monitorElTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3elTb4b4b4) Te6edf3elTb4b4b4.Te6edf3scrollTop Tff7b72= Te6edf3elTb4b4b4.Te6edf3scrollHeightTb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3methodsTff7b72: Tb4b4b4{

T8b949e// ── i18n ─────────────────────────────────────────────────
Te6edf3tTb4b4b4(Te6edf3keyTb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4(Tffa657windowTb4b4b4.Te6edf3i18nTb4b4b4[Tff7b72thisTb4b4b4.Te6edf3langTb4b4b4] Tff7b72&& Tffa657windowTb4b4b4.Te6edf3i18nTb4b4b4[Tff7b72thisTb4b4b4.Te6edf3langTb4b4b4]Tb4b4b4[Te6edf3keyTb4b4b4]Tb4b4b4) Tff7b72|| Te6edf3keyTb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3setLangTb4b4b4(Te6edf3langTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3lang Tff7b72= Te6edf3langTb4b4b4;
Tffa657windowTb4b4b4.Te6edf3setLangTb4b4b4(Te6edf3langTb4b4b4)Tb4b4b4;
Te6edf3localStorageTb4b4b4.Te6edf3setItemTb4b4b4(Ta5d6ff'lang'Tb4b4b4, Te6edf3langTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Theme ─────────────────────────────────────────────────
Te6edf3applyThemeTb4b4b4(Te6edf3themeTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3theme Tff7b72= Te6edf3themeTb4b4b4;
Tffa657documentTb4b4b4.Te6edf3documentElementTb4b4b4.Te6edf3setAttributeTb4b4b4(Ta5d6ff'data-theme'Tb4b4b4, Te6edf3themeTb4b4b4)Tb4b4b4;
Te6edf3localStorageTb4b4b4.Te6edf3setItemTb4b4b4(Ta5d6ff'theme'Tb4b4b4, Te6edf3themeTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3toggleThemeTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3applyThemeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3theme Tff7b72=== Ta5d6ff'dark' Tff7b72? Ta5d6ff'light' Tff7b72: Ta5d6ff'dark'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Logging ──────────────────────────────────────────────
Te6edf3addLogTb4b4b4(Te6edf3typeTb4b4b4, Te6edf3pfxTb4b4b4, Te6edf3txtTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3logTb4b4b4.Te6edf3pushTb4b4b4(Tb4b4b4{ Te6edf3typeTb4b4b4, Te6edf3pfxTb4b4b4, Te6edf3txt Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3progressLineIdx Tff7b72= Tff7b72-T79c0ff1Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3setProgressLineTb4b4b4(Te6edf3txtTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3progressLineIdx Tff7b72>= T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3logTb4b4b4[Tff7b72thisTb4b4b4.Te6edf3progressLineIdxTb4b4b4] Tff7b72= Tb4b4b4{ Te6edf3typeTff7b72: Ta5d6ff'prog'Tb4b4b4, Te6edf3pfxTff7b72: Ta5d6ff' 'Tb4b4b4, Te6edf3txt Tb4b4b4}Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3logTb4b4b4.Te6edf3pushTb4b4b4(Tb4b4b4{ Te6edf3typeTff7b72: Ta5d6ff'prog'Tb4b4b4, Te6edf3pfxTff7b72: Ta5d6ff' 'Tb4b4b4, Te6edf3txt Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3progressLineIdx Tff7b72= Tff7b72thisTb4b4b4.Te6edf3logTb4b4b4.Te6edf3length Tff7b72- T79c0ff1Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3clearLogTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3log Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3progressLineIdx Tff7b72= Tff7b72-T79c0ff1Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Device change ─────────────────────────────────────────
Te6edf3onDeviceChangeTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3selectedDevice Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72= Ta5d6ff'info'Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// Meshtastic / MeshCore are separate mesh ecosystems, not Reticulum firmwares
Te6edf3isNonReticulumTb4b4b4(Te6edf3vTb4b4b4) Tb4b4b4{
Tff7b72return Ta5d6ff/\/(meshtastic|meshcore)\//Tb4b4b4.Te6edf3testTb4b4b4(Te6edf3vTb4b4b4.Te6edf3firmware_zipTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Direct links (?d=<device>&v=<variant>) ─────────────────
Te6edf3applyDirectLinkTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3params Tff7b72= Tff7b72new Te6edf3URLSearchParamsTb4b4b4(Tffa657windowTb4b4b4.Te6edf3locationTb4b4b4.Te6edf3searchTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3deviceId Tff7b72= Te6edf3paramsTb4b4b4.Te6edf3getTb4b4b4(Ta5d6ff'd'Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3deviceIdTb4b4b4) Tff7b72returnTb4b4b4;

Tff7b72let Te6edf3device Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3grp Tff7b72of Tff7b72thisTb4b4b4.Te6edf3deviceGroupsTb4b4b4) Tb4b4b4{
Te6edf3device Tff7b72= Te6edf3grpTb4b4b4.Te6edf3devicesTb4b4b4.Te6edf3findTb4b4b4(Te6edf3d Tb4b4b4=> Te6edf3DEVICE_SHORT_IDTb4b4b4[Te6edf3dTb4b4b4.Te6edf3nameTb4b4b4] Tff7b72=== Te6edf3deviceIdTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3deviceTb4b4b4) Tff7b72breakTb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3deviceTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedDevice Tff7b72= Te6edf3deviceTb4b4b4;

Tff7b72const Te6edf3variantId Tff7b72= Te6edf3paramsTb4b4b4.Te6edf3getTb4b4b4(Ta5d6ff'v'Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3variantIdTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3variant Tff7b72= Te6edf3deviceTb4b4b4.Te6edf3variantsTb4b4b4.Te6edf3findTb4b4b4(Te6edf3va Tb4b4b4=> Te6edf3variantShortIdTb4b4b4(Te6edf3vaTb4b4b4.Te6edf3nameTb4b4b4) Tff7b72=== Te6edf3variantIdTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3variantTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3isNonReticulumTb4b4b4(Te6edf3variantTb4b4b4)Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3showOtherFirmwares Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72= Te6edf3variantTb4b4b4;
Tb4b4b4}
Tb4b4b4}

Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72= Ta5d6ff'info'Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3flasherLinkUrlTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3selectedDeviceTb4b4b4) Tff7b72return Ta5d6ff''Tb4b4b4;
Tff7b72const Te6edf3params Tff7b72= Tff7b72new Te6edf3URLSearchParamsTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3paramsTb4b4b4.Te6edf3setTb4b4b4(Ta5d6ff'd'Tb4b4b4, Te6edf3DEVICE_SHORT_IDTb4b4b4[Tff7b72thisTb4b4b4.Te6edf3selectedDeviceTb4b4b4.Te6edf3nameTb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3selectedVariantTb4b4b4) Te6edf3paramsTb4b4b4.Te6edf3setTb4b4b4(Ta5d6ff'v'Tb4b4b4, Te6edf3variantShortIdTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3selectedVariantTb4b4b4.Te6edf3nameTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72return Ta5d6ff`Tffd700${Tffa657windowTb4b4b4.Te6edf3locationTb4b4b4.Te6edf3originTffd700}Tffd700${Tffa657windowTb4b4b4.Te6edf3locationTb4b4b4.Te6edf3pathnameTffd700}Ta5d6ff?Tffd700${Te6edf3paramsTb4b4b4.Te6edf3toStringTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3copyFlasherLinkTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3url Tff7b72= Tff7b72thisTb4b4b4.Te6edf3flasherLinkUrlTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3urlTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72await Te6edf3navigatorTb4b4b4.Te6edf3clipboardTb4b4b4.Te6edf3writeTextTb4b4b4(Te6edf3urlTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3linkCopied Tff7b72= Tff7b72trueTb4b4b4;
Te6edf3setTimeoutTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3linkCopied Tff7b72= Tff7b72falseTb4b4b4; Tb4b4b4}Tb4b4b4, T79c0ff1500Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tffa657windowTb4b4b4.Te6edf3promptTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'hw.info.copy_link_manual'Tb4b4b4)Tb4b4b4, Te6edf3urlTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,

T8b949e// ── Request serial port ───────────────────────────────────
Tff7b72async Te6edf3requestPortTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4) Tb4b4b4{
Te6edf3alertTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'alert.no_serial'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72return Tff7b72nullTb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedPortTb4b4b4) Tff7b72return Tff7b72thisTb4b4b4.Te6edf3connectedPortTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3port Tff7b72= Tff7b72await Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4{ Te6edf3filtersTff7b72: Tb4b4b4[Tb4b4b4] Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedPort Tff7b72= Te6edf3portTb4b4b4;
Tff7b72return Te6edf3portTb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72return Tff7b72nullTb4b4b4; T8b949e// user cancelled
Tb4b4b4}
Tb4b4b4}Tb4b4b4,

T8b949e// ── Detect / disconnect port ──────────────────────────────
Tff7b72async Te6edf3detectDeviceTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4) Tb4b4b4{
Te6edf3alertTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'alert.no_serial'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72returnTb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3clearLogTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.detecting'Tb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3port Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3ports Tff7b72= Tff7b72await Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4.Te6edf3getPortsTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3portFromCache Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3portsTb4b4b4.Te6edf3length Tff7b72=== T79c0ff1Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'Found previously granted port'Tb4b4b4)Tb4b4b4;
Te6edf3port Tff7b72= Te6edf3portsTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4;
Te6edf3portFromCache Tff7b72= Tff7b72trueTb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3port Tff7b72= Tff7b72await Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4{ Te6edf3filtersTff7b72: Tb4b4b4[Tb4b4b4] Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3portTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedPort Tff7b72= Te6edf3portTb4b4b4;

T8b949e// ── Phase 1: try RNode firmware ─────────────────────────
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Detecting RNode...'Tb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3rnodeDetected Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72let Te6edf3phase1PortUnavailable Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3rnode Tff7b72= Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ok Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3okTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3e Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3fwVer Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72try Tb4b4b4{ Te6edf3fwVer Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getFirmwareVersionTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72let Te6edf3platform Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72try Tb4b4b4{
Te6edf3platform Tff7b72= Tff7b72await Tffa657PromiseTb4b4b4.Te6edf3raceTb4b4b4(Tb4b4b4[
Te6edf3rnodeTb4b4b4.Te6edf3getPlatformTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff1500Tb4b4b4)Tb4b4b4.Te6edf3thenTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tff7b72nullTb4b4b4)Tb4b4b4,
Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;

Tff7b72const Te6edf3productId Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_PRODUCTTb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3modelId Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_MODELTb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3hwRev Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_HW_REVTb4b4b4]Tb4b4b4;

Tff7b72if Tb4b4b4(Te6edf3productId Tff7b72=== T79c0ff0xFFTb4b4b4) Tb4b4b4{
T8b949e// EEPROM blank β€” RNode firmware present but device not provisioned
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'RNode firmware detected but EEPROM is unprovisioned'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'falling back to chip detection...'Tb4b4b4)Tb4b4b4;
T8b949e// fall through to Phase 2
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3rnodeDetected Tff7b72= Tff7b72trueTb4b4b4;

Tff7b72let Te6edf3name Tff7b72= Ta5d6ff`Ta5d6ffproduct 0xTffd700${Te6edf3productIdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tffd700}Ta5d6ff / model 0xTffd700${Te6edf3modelIdTff7b72?Tb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4;
Te6edf3outerTff7b72: Tff7b72for Tb4b4b4(Tff7b72const Te6edf3grp Tff7b72of Te6edf3DEVICE_GROUPSTb4b4b4) Tb4b4b4{
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3dev Tff7b72of Te6edf3grpTb4b4b4.Te6edf3devicesTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3devTb4b4b4.Te6edf3product_id Tff7b72=== Te6edf3productIdTb4b4b4) Tb4b4b4{
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3v Tff7b72of Te6edf3devTb4b4b4.Te6edf3variantsTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tb4b4b4(Te6edf3vTb4b4b4.Te6edf3mapped_model_id Tff7b72?? Te6edf3vTb4b4b4.Te6edf3model_idTb4b4b4) Tff7b72=== Te6edf3modelIdTb4b4b4) Tb4b4b4{
Te6edf3name Tff7b72= Te6edf3devTb4b4b4.Te6edf3nameTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedDevice Tff7b72= Te6edf3devTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72= Te6edf3vTb4b4b4;
Tff7b72break Te6edf3outerTb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3productId Tff7b72=== T79c0ff0xF0Tb4b4b4) Tb4b4b4{
Te6edf3name Tff7b72= Ta5d6ff'Homebrew'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedDevice Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72= Tff7b72nullTb4b4b4;
Tb4b4b4}

Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72= Te6edf3nameTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedFwVer Tff7b72= Te6edf3fwVer Tff7b72|| Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72= Te6edf3platformTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3detectedChip Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72const Te6edf3fwVerStr Tff7b72= Te6edf3fwVer Tff7b72? Ta5d6ff`Ta5d6ff (RNode_Firmware Tffd700${Te6edf3fwVerTffd700}Ta5d6ff)Ta5d6ff` Tff7b72: Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffRNode detected: Tffd700${Te6edf3nameTffd700}Tffd700${Te6edf3fwVerStrTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff`Ta5d6ffDetected: Tffd700${Te6edf3nameTffd700}Ta5d6ff`Tb4b4b4;
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffphase 1: Tffd700${Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72if Tb4b4b4(Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4.Te6edf3includesTb4b4b4(Ta5d6ff'Failed to open port'Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3phase1PortUnavailable Tff7b72= Tff7b72trueTb4b4b4;
Tb4b4b4}
Tb4b4b4}

T8b949e// If the cached port couldn't be opened the stored VID belongs to the
T8b949e// old (now-disconnected) device and cannot be trusted. Ask the user to
T8b949e// select the device that is actually plugged in right now.
Tff7b72if Tb4b4b4(Te6edf3portFromCache Tff7b72&& Te6edf3phase1PortUnavailableTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'Cached port unavailable β€” please select the connected device'Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3newPort Tff7b72= Tff7b72await Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4{ Te6edf3filtersTff7b72: Tb4b4b4[Tb4b4b4] Tb4b4b4}Tb4b4b4)Tb4b4b4;
Te6edf3port Tff7b72= Te6edf3newPortTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedPort Tff7b72= Te6edf3portTb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{
Tff7b72returnTb4b4b4; T8b949e// user cancelled
Tb4b4b4}
Tb4b4b4}

Tff7b72if Tb4b4b4(Te6edf3rnodeDetectedTb4b4b4) Tff7b72returnTb4b4b4;

T8b949e// give the OS a moment to fully release the device before re-opening
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff200Tb4b4b4)Tb4b4b4;

T8b949e// ── Phase 2a: VID-based nRF52 detection (skip esptool entirely) ────
Tff7b72const Te6edf3portInfo Tff7b72= Te6edf3portTb4b4b4.Te6edf3getInfoTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3NRF52_VIDSTb4b4b4.Te6edf3includesTb4b4b4(Te6edf3portInfoTb4b4b4.Te6edf3usbVendorIdTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3detectedChip Tff7b72= Ta5d6ff'nRF52'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffnRF52 device detected (VID 0xTffd700${Te6edf3portInfoTb4b4b4.Te6edf3usbVendorIdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff4Tb4b4b4,Ta5d6ff'0'Tb4b4b4)Tffd700}Ta5d6ff) β€” select your board and flashTa5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.nrf52_detected'Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72returnTb4b4b4;
Tb4b4b4}

T8b949e// ── Phase 2: esptool chip detection (fresh board) ───────
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'no RNode firmware β€” detecting chip via bootloader...'Tb4b4b4)Tb4b4b4;

Tff7b72let Te6edf3transportTb4b4b4;
Tff7b72try Tb4b4b4{
Te6edf3transport Tff7b72= Tff7b72new Tffa657windowTb4b4b4.Te6edf3TransportTb4b4b4(Te6edf3portTb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4;
Te6edf3transportTb4b4b4.Te6edf3trace Tff7b72= Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{Tb4b4b4}Tb4b4b4;
Tff7b72const Te6edf3self Tff7b72= Tff7b72thisTb4b4b4;
Tff7b72const Te6edf3esploader Tff7b72= Tff7b72new Tffa657windowTb4b4b4.Te6edf3ESPLoaderTb4b4b4(Tb4b4b4{
Te6edf3transportTb4b4b4, Te6edf3baudrateTff7b72: T79c0ff115200Tb4b4b4, Te6edf3debugLoggingTff7b72: Tff7b72falseTb4b4b4, Te6edf3enableTracingTff7b72: Tff7b72falseTb4b4b4,
Te6edf3terminalTff7b72: Tb4b4b4{
Te6edf3cleanTb4b4b4(Tb4b4b4) Tb4b4b4{Tb4b4b4}Tb4b4b4,
Te6edf3writeLineTb4b4b4(Te6edf3dTb4b4b4) Tb4b4b4{ Tff7b72if Tb4b4b4(Te6edf3dTff7b72?Tb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3selfTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Te6edf3dTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4; Tb4b4b4}Tb4b4b4,
Te6edf3writeTb4b4b4(Tb4b4b4) Tb4b4b4{Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;

Tff7b72const Te6edf3chipDesc Tff7b72= Tff7b72await Te6edf3esploaderTb4b4b4.Te6edf3mainTb4b4b4(Tb4b4b4)Tb4b4b4;
T8b949e// main() returns verbose description; CHIP_NAME is the normalised ID for matching
Tff7b72const Te6edf3chipName Tff7b72= Te6edf3esploaderTb4b4b4.Te6edf3chipTff7b72?Tb4b4b4.Te6edf3CHIP_NAME Tff7b72?? Te6edf3chipDescTb4b4b4.Te6edf3splitTb4b4b4(Ta5d6ff' 'Tb4b4b4)Tb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3flashSize Tff7b72= Tff7b72await Te6edf3esploaderTb4b4b4.Te6edf3detectFlashSizeTb4b4b4(Tb4b4b4)Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3detectedChip Tff7b72= Te6edf3chipNameTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3detectedChipDesc Tff7b72= Te6edf3chipDescTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3detectedFlash Tff7b72= Te6edf3flashSizeTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffChip: Tffd700${Te6edf3chipDescTffd700}Ta5d6ff Flash: Tffd700${Te6edf3flashSizeTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;

T8b949e// Try to uniquely identify the board
Tff7b72const Te6edf3allDevices Tff7b72= Te6edf3DEVICE_GROUPSTb4b4b4.Te6edf3flatMapTb4b4b4(Te6edf3g Tb4b4b4=> Te6edf3gTb4b4b4.Te6edf3devicesTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3matches Tff7b72= Te6edf3allDevicesTb4b4b4.Te6edf3filterTb4b4b4(Te6edf3d Tb4b4b4=> Tb4b4b4{
Tff7b72const Te6edf3hw Tff7b72= Te6edf3DEVICE_HARDWARETb4b4b4[Te6edf3dTb4b4b4.Te6edf3nameTb4b4b4]Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3hwTb4b4b4) Tff7b72return Tff7b72falseTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3hwTb4b4b4.Te6edf3chip Tff7b72!== Te6edf3chipNameTb4b4b4) Tff7b72return Tff7b72falseTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3hwTb4b4b4.Te6edf3flash Tff7b72!== Te6edf3flashSizeTb4b4b4) Tff7b72return Tff7b72falseTb4b4b4;
Tff7b72return Tff7b72trueTb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;

Tff7b72if Tb4b4b4(Te6edf3matchesTb4b4b4.Te6edf3length Tff7b72=== T79c0ff1Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3selectedDevice Tff7b72= Te6edf3matchesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72= Te6edf3matchesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4.Te6edf3nameTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3detectedChip Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3detectedChipDesc Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3detectedFlash Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffidentified: Tffd700${Te6edf3matchesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4.Te6edf3nameTffd700}Ta5d6ff β€” select a variantTa5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff`Ta5d6ffIdentified: Tffd700${Te6edf3matchesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4.Te6edf3nameTffd700}Ta5d6ff`Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72const Te6edf3names Tff7b72= Te6edf3matchesTb4b4b4.Te6edf3mapTb4b4b4(Te6edf3d Tb4b4b4=> Te6edf3dTb4b4b4.Te6edf3nameTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffCompatible: Tffd700${Te6edf3namesTb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff', 'Tb4b4b4) Tff7b72|| Ta5d6ff'none in list'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'Device list filtered β€” select your board and variant'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff`Tffd700${Te6edf3chipNameTffd700}Ta5d6ff Β· Tffd700${Te6edf3flashSizeTffd700}Ta5d6ff`Tb4b4b4;
Tb4b4b4}

T8b949e// Reset device back to normal
Tff7b72try Tb4b4b4{
Tff7b72await Te6edf3transportTb4b4b4.Te6edf3setDTRTb4b4b4(Tff7b72falseTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3transportTb4b4b4.Te6edf3setRTSTb4b4b4(Tff7b72trueTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff100Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3transportTb4b4b4.Te6edf3setRTSTb4b4b4(Tff7b72falseTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3transportTb4b4b4.Te6edf3setDTRTb4b4b4(Tff7b72falseTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3transportTff7b72?Tb4b4b4.Te6edf3readerTb4b4b4) Tb4b4b4{ Tff7b72await Te6edf3transportTb4b4b4.Te6edf3readerTb4b4b4.Te6edf3cancelTb4b4b4(Tb4b4b4)Tb4b4b4; Te6edf3transportTb4b4b4.Te6edf3readerTb4b4b4.Te6edf3releaseLockTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3transportTff7b72?Tb4b4b4.Te6edf3writerTb4b4b4) Te6edf3transportTb4b4b4.Te6edf3writerTb4b4b4.Te6edf3releaseLockTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3eTb4b4b4.Te6edf3name Tff7b72!== Ta5d6ff'NotFoundError'Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4.Te6edf3includesTb4b4b4(Ta5d6ff'Failed to open port'Tb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'Put the device into bootloader mode: hold the BOOT button, press Reset (or reconnect USB), then try detecting again'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4.Te6edf3includesTb4b4b4(Ta5d6ff'Failed to connect with the device'Tb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3info Tff7b72= Te6edf3portTff7b72?Tb4b4b4.Te6edf3getInfoTff7b72?Tb4b4b4.Tb4b4b4(Tb4b4b4) Tff7b72?? Tb4b4b4{Tb4b4b4}Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3infoTb4b4b4.Te6edf3usbVendorId Tff7b72=== T79c0ff0x1a86 Tff7b72&& Te6edf3infoTb4b4b4.Te6edf3usbProductId Tff7b72=== T79c0ff0x55d3Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Ta5d6ff'Connected to USB-to-Serial port'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'If your device has two USB ports, connect to the JTAG port instead'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'Hold BOOT while powering up to enter bootloader mode, then try detecting again'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedPort Tff7b72= Tff7b72nullTb4b4b4; Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72= Ta5d6ff''Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72= Tff7b72nullTb4b4b4;
Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72=== Ta5d6ff'wifi' Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3wifiSupportedTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72= Ta5d6ff'info'Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72=== Ta5d6ff'ethernet' Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3ethernetSupportedTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72= Ta5d6ff'info'Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72=== Ta5d6ff'misc' Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3miscSupportedTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72= Ta5d6ff'info'Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedFwVerTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3selectTabTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3cfgTabTb4b4b4, Tff7b72trueTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,

T8b949e// graceful disconnect from the UI button: tell RNode firmware the
T8b949e// host is leaving (CMD_LEAVE 0xFF) before releasing the port
Tff7b72async Te6edf3disconnectDeviceTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3port Tff7b72= Tff7b72thisTb4b4b4.Te6edf3connectedPortTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3port Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3connectedFwVerTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.disconnecting'Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{
T8b949e// a previous operation may have left the port open β€” reuse it
T8b949e// instead of re-opening (open() throws on an already-open port)
Tff7b72const Te6edf3alreadyOpen Tff7b72= Tff7b72!Tff7b72!Tb4b4b4(Te6edf3portTb4b4b4.Te6edf3readable Tff7b72&& Te6edf3portTb4b4b4.Te6edf3writableTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3rnode Tff7b72= Te6edf3alreadyOpen Tff7b72? Tff7b72new Te6edf3RNodeTb4b4b4(Te6edf3portTb4b4b4) Tff7b72: Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{
T8b949e// DETECT first: confirms the link is alive and forces the node
T8b949e// into CONNECTED state, so LEAVE always produces the
T8b949e// disconnect edge (and its melody) on the device
Tff7b72const Te6edf3ok Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3okTb4b4b4) Tb4b4b4{
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3leaveTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff100Tb4b4b4)Tb4b4b4; T8b949e// let the command flush before closing
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Disconnect signalled to device (CMD_LEAVE)'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Ta5d6ff'Device did not respond to detect β€” disconnecting anyway'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Ta5d6ff`Ta5d6ffDisconnect signal failed: Tffd700${Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3disconnectPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

Te6edf3disconnectPortTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// safety net: if any code path left the cached port open, close it
T8b949e// so the device is actually released back to the OS
Tff7b72const Te6edf3port Tff7b72= Tff7b72thisTb4b4b4.Te6edf3connectedPortTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3port Tff7b72&& Tb4b4b4(Te6edf3portTb4b4b4.Te6edf3readable Tff7b72|| Te6edf3portTb4b4b4.Te6edf3writableTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{ Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4.Tff7b72catchTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{Tb4b4b4}Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3connectedPort Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedFwVer Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3detectedChip Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3detectedChipDesc Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3detectedFlash Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3sndEnabled Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72=== Ta5d6ff'misc'Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72= Ta5d6ff'info'Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// The dropdown next to Connect picks a transport, but USB and WebSocket
T8b949e// each only work on one kind of origin (see isSecureContext above) - so
T8b949e// choosing the one this origin doesn't support navigates to the sibling
T8b949e// deployment that does, instead of trying to switch in-page.
Te6edf3onTransportChangeTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3wantUsb Tff7b72= Tff7b72thisTb4b4b4.Te6edf3transportChoice Tff7b72=== Ta5d6ff'usb'Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3wantUsb Tff7b72=== Tff7b72thisTb4b4b4.Te6edf3isSecureContextTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72const Te6edf3target Tff7b72= Te6edf3wantUsb Tff7b72? Tff7b72thisTb4b4b4.Te6edf3brandTb4b4b4.Te6edf3usbUrl Tff7b72: Tff7b72thisTb4b4b4.Te6edf3brandTb4b4b4.Te6edf3wsUrlTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3targetTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3transportChoice Tff7b72= Tff7b72thisTb4b4b4.Te6edf3isSecureContext Tff7b72? Ta5d6ff'usb' Tff7b72: Ta5d6ff'ws'Tb4b4b4;
Tff7b72returnTb4b4b4;
Tb4b4b4}
Tffa657windowTb4b4b4.Te6edf3locationTb4b4b4.Te6edf3href Tff7b72= Te6edf3targetTb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Detect an already-running RNode over the network ──────
T8b949e// Node configuration (withRNode()) and detect/reboot/dump/screen all work
T8b949e// over this transport too. Flashing and erase still require USB
T8b949e// bootloader access (esptool/nRF52 DFU), which has no network
T8b949e// equivalent, so those stay serial-only and keep using
T8b949e// connectedPort/requestPort() exclusively.
Tff7b72async Te6edf3detectDeviceOverNetworkTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3host Tff7b72= Tff7b72thisTb4b4b4.Te6edf3networkHostTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3hostTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72const Te6edf3url Tff7b72= Ta5d6ff`Ta5d6ffws://Tffd700${Te6edf3hostTffd700}Ta5d6ff:7634Ta5d6ff`Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3clearLogTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.detecting'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff`Ta5d6ffConnecting to Tffd700${Te6edf3urlTffd700}Ta5d6ff...Ta5d6ff`Tb4b4b4)Tb4b4b4;

Tff7b72let Te6edf3rnode Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72try Tb4b4b4{
Te6edf3rnode Tff7b72= Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromWebSocketTb4b4b4(Te6edf3urlTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ok Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3okTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'No RNode detected at that address'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.network_not_detected'Tb4b4b4)Tb4b4b4;
Tff7b72returnTb4b4b4;
Tb4b4b4}

Tff7b72const Te6edf3e Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3fwVer Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72try Tb4b4b4{ Te6edf3fwVer Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getFirmwareVersionTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72let Te6edf3platform Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72try Tb4b4b4{
Te6edf3platform Tff7b72= Tff7b72await Tffa657PromiseTb4b4b4.Te6edf3raceTb4b4b4(Tb4b4b4[
Te6edf3rnodeTb4b4b4.Te6edf3getPlatformTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff1500Tb4b4b4)Tb4b4b4.Te6edf3thenTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tff7b72nullTb4b4b4)Tb4b4b4,
Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4}

Tff7b72const Te6edf3productId Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_PRODUCTTb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3modelId Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_MODELTb4b4b4]Tb4b4b4;

Tff7b72let Te6edf3name Tff7b72= Ta5d6ff`Ta5d6ffproduct 0xTffd700${Te6edf3productIdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tffd700}Ta5d6ff / model 0xTffd700${Te6edf3modelIdTff7b72?Tb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4;
Te6edf3outerTff7b72: Tff7b72for Tb4b4b4(Tff7b72const Te6edf3grp Tff7b72of Te6edf3DEVICE_GROUPSTb4b4b4) Tb4b4b4{
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3dev Tff7b72of Te6edf3grpTb4b4b4.Te6edf3devicesTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3devTb4b4b4.Te6edf3product_id Tff7b72=== Te6edf3productIdTb4b4b4) Tb4b4b4{
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3v Tff7b72of Te6edf3devTb4b4b4.Te6edf3variantsTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tb4b4b4(Te6edf3vTb4b4b4.Te6edf3mapped_model_id Tff7b72?? Te6edf3vTb4b4b4.Te6edf3model_idTb4b4b4) Tff7b72=== Te6edf3modelIdTb4b4b4) Tb4b4b4{
Te6edf3name Tff7b72= Te6edf3devTb4b4b4.Te6edf3nameTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedDevice Tff7b72= Te6edf3devTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72= Te6edf3vTb4b4b4;
Tff7b72break Te6edf3outerTb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3productId Tff7b72=== T79c0ff0xF0Tb4b4b4) Tb4b4b4{
Te6edf3name Tff7b72= Ta5d6ff'Homebrew'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedDevice Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72= Tff7b72nullTb4b4b4;
Tb4b4b4}

Tff7b72thisTb4b4b4.Te6edf3connectedNetworkUrl Tff7b72= Te6edf3urlTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72= Te6edf3nameTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedFwVer Tff7b72= Te6edf3fwVer Tff7b72|| Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72= Te6edf3platformTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3detectedChip Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72const Te6edf3fwVerStr Tff7b72= Te6edf3fwVer Tff7b72? Ta5d6ff`Ta5d6ff (RNode_Firmware Tffd700${Te6edf3fwVerTffd700}Ta5d6ff)Ta5d6ff` Tff7b72: Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffRNode detected over network: Tffd700${Te6edf3nameTffd700}Tffd700${Te6edf3fwVerStrTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff`Ta5d6ffDetected: Tffd700${Te6edf3nameTffd700}Ta5d6ff`Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Tffd700${Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.network_connect_failed'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4{ Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4} Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72=== Ta5d6ff'wifi' Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3wifiSupportedTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72= Ta5d6ff'info'Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72=== Ta5d6ff'ethernet' Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3ethernetSupportedTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72= Ta5d6ff'info'Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72=== Ta5d6ff'misc' Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3miscSupportedTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72= Ta5d6ff'info'Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedFwVerTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3selectTabTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3cfgTabTb4b4b4, Tff7b72trueTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3disconnectNetworkDeviceTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3url Tff7b72= Tff7b72thisTb4b4b4.Te6edf3connectedNetworkUrlTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3url Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3connectedFwVerTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.disconnecting'Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3rnode Tff7b72= Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromWebSocketTb4b4b4(Te6edf3urlTb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3ok Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3okTb4b4b4) Tb4b4b4{
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3leaveTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff100Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Disconnect signalled to device (CMD_LEAVE)'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Ta5d6ff'Device did not respond to detect β€” disconnecting anyway'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Ta5d6ff`Ta5d6ffDisconnect signal failed: Tffd700${Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3connectedNetworkUrl Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedFwVer Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedDevice Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3selectedVariant Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72=== Ta5d6ff'misc'Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72= Ta5d6ff'info'Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Fetch firmware zip from server ────────────────────────
Tff7b72async Te6edf3fetchFirmwareBlobTb4b4b4(Te6edf3urlTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3resp Tff7b72= Tff7b72await Te6edf3fetchTb4b4b4(Te6edf3urlTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3respTb4b4b4.Te6edf3okTb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff`Ta5d6ffHTTP Tffd700${Te6edf3respTb4b4b4.Te6edf3statusTffd700}Ta5d6ff fetching Tffd700${Te6edf3urlTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3respTb4b4b4.Te6edf3blobTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Anonymous flash-stats tracking (best-effort, never blocks) ─
Te6edf3trackFlashTb4b4b4(Te6edf3deviceTb4b4b4, Te6edf3variantTb4b4b4) Tb4b4b4{
Te6edf3fetchTb4b4b4(Ta5d6ff'/api/track.php'Tb4b4b4, Tb4b4b4{
Te6edf3methodTff7b72: Ta5d6ff'POST'Tb4b4b4,
Te6edf3headersTff7b72: Tb4b4b4{ Ta5d6ff'Content-Type'Tff7b72: Ta5d6ff'application/json' Tb4b4b4}Tb4b4b4,
Te6edf3bodyTff7b72: Tffa657JSONTb4b4b4.Te6edf3stringifyTb4b4b4(Tb4b4b4{ Te6edf3deviceTff7b72: Te6edf3deviceTb4b4b4.Te6edf3nameTb4b4b4, Te6edf3variantTff7b72: Te6edf3variantTb4b4b4.Te6edf3nameTb4b4b4, Te6edf3platformTff7b72: Te6edf3variantTb4b4b4.Te6edf3platform Tb4b4b4}Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4.Tff7b72catchTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Main flash pipeline ───────────────────────────────────
Tff7b72async Te6edf3flashAllTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3canFlashTb4b4b4) Tff7b72returnTb4b4b4;

Tff7b72const Te6edf3device Tff7b72= Tff7b72thisTb4b4b4.Te6edf3selectedDeviceTb4b4b4;
Tff7b72const Te6edf3variant Tff7b72= Tff7b72thisTb4b4b4.Te6edf3selectedVariantTb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff0Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3clearLogTb4b4b4(Tb4b4b4)Tb4b4b4;

Tff7b72let Te6edf3port Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72try Tb4b4b4{
T8b949e// 1. Download firmware *before* prompting for the port. The device
T8b949e// has to already be in the bootloader by the time it's picked
T8b949e// (nRF52 boards need to be in DFU mode first β€” use the "Enter
T8b949e// DFU Mode" advanced tool, or a manual double-press RST as a
T8b949e// fallback), and Adafruit's bootloader auto-continues into the
T8b949e// application after a few idle seconds. Fetching the zip after
T8b949e// the port is already selected burns that window on network
T8b949e// time β€” on a slow connection the bootloader can time out and
T8b949e// boot the application before a single DFU packet goes out.
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff`Ta5d6ffDownloading Tffd700${Te6edf3variantTb4b4b4.Te6edf3firmware_zipTb4b4b4.Te6edf3splitTb4b4b4(Ta5d6ff'/'Tb4b4b4)Tb4b4b4.Te6edf3popTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff...Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.downloading'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3blob Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3fetchFirmwareBlobTb4b4b4(Te6edf3variantTb4b4b4.Te6edf3firmware_zipTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Firmware downloaded'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff5Tb4b4b4;

Te6edf3port Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3portTb4b4b4) Tff7b72returnTb4b4b4;

T8b949e// 2. Flash β€” dispatch by platform
Tff7b72let Te6edf3flashStepTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3variantTb4b4b4.Te6edf3platform Tff7b72=== Ta5d6ff'nrf52'Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3binName Tff7b72= Te6edf3variantTb4b4b4.Te6edf3firmware_zipTb4b4b4.Te6edf3splitTb4b4b4(Ta5d6ff'/'Tb4b4b4)Tb4b4b4.Te6edf3popTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/\.zip$/iTb4b4b4, Ta5d6ff'.bin'Tb4b4b4)Tb4b4b4;
Te6edf3flashStep Tff7b72= Te6edf3binNameTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'rnode_firmware'Tb4b4b4) Tff7b72? Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.flashing_fw'Tb4b4b4) Tff7b72: Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.flashing'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72const Te6edf3files Tff7b72= Tffa657ObjectTb4b4b4.Te6edf3valuesTb4b4b4(Te6edf3variantTb4b4b4.Te6edf3flash_configTb4b4b4.Te6edf3flash_filesTb4b4b4)Tb4b4b4;
Te6edf3flashStep Tff7b72= Te6edf3filesTb4b4b4.Te6edf3someTb4b4b4(Te6edf3f Tb4b4b4=> Te6edf3fTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'rnode_firmware'Tb4b4b4)Tb4b4b4) Tff7b72? Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.flashing_fw'Tb4b4b4) Tff7b72: Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.flashing'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3variantTb4b4b4.Te6edf3platform Tff7b72=== Ta5d6ff'nrf52'Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3doNrf52FlashTb4b4b4(Te6edf3portTb4b4b4, Te6edf3blobTb4b4b4, Te6edf3flashStepTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
T8b949e// ESP32: retry once with bootloader reset on port error
Tff7b72try Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3doEsp32FlashTb4b4b4(Te6edf3portTb4b4b4, Te6edf3blobTb4b4b4, Te6edf3variantTb4b4b4.Te6edf3flash_configTb4b4b4, Te6edf3flashStepTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72&& Ta5d6ff/open|port|access/iTb4b4b4.Te6edf3testTb4b4b4(Te6edf3eTb4b4b4.Te6edf3messageTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Ta5d6ff`Ta5d6ffPort error: Tffd700${Te6edf3eTb4b4b4.Te6edf3messageTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Attempting bootloader reset...'Tb4b4b4)Tb4b4b4;
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3enterBootloaderTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Retrying flash...'Tb4b4b4)Tb4b4b4;
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3doEsp32FlashTb4b4b4(Te6edf3portTb4b4b4, Te6edf3blobTb4b4b4, Te6edf3variantTb4b4b4.Te6edf3flash_configTb4b4b4, Te6edf3flashStepTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72throw Te6edf3eTb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff90Tb4b4b4;

T8b949e// 3. Post-flash RNode config
Tff7b72if Tb4b4b4(Te6edf3variantTb4b4b4.Te6edf3needs_provisioningTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Waiting for device to boot...'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.rebooting'Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tb4b4b4[Ta5d6ff'MeshAdventurer-S3'Tb4b4b4, Ta5d6ff'Aethernode-S3'Tb4b4b4]Tb4b4b4.Te6edf3includesTb4b4b4(Te6edf3deviceTb4b4b4.Te6edf3nameTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'DIY dual-port device: unplug and reconnect using the USB-to-Serial port (not the JTAG port used for flashing) before the reconnect attempt below'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff5000Tb4b4b4)Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reconnecting to RNode...'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.connecting'Tb4b4b4)Tb4b4b4;

Tff7b72let Te6edf3rnode Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3attempt Tff7b72= T79c0ff0Tb4b4b4; Te6edf3attempt Tff7b72< T79c0ff15Tb4b4b4; Te6edf3attemptTff7b72++Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3attempt Tff7b72> T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3attempt Tff7b72=== T79c0ff3Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'warn.press_rst_blank'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffnot ready, retrying... (Tffd700${Te6edf3attemptTffd700}Ta5d6ff/15)Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff2000Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72try Tb4b4b4{
T8b949e// After native USB re-enumeration the original port object may be stale;
T8b949e// prefer a freshly enumerated port from getPorts() if one is available.
Tff7b72let Te6edf3connectPort Tff7b72= Te6edf3portTb4b4b4;
Tff7b72const Te6edf3freshPorts Tff7b72= Tff7b72await Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4.Te6edf3getPortsTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3freshPortsTb4b4b4.Te6edf3length Tff7b72=== T79c0ff1Tb4b4b4) Te6edf3connectPort Tff7b72= Te6edf3freshPortsTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4;

Tff7b72const Te6edf3r Tff7b72= Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3connectPortTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ok Tff7b72= Tff7b72await Te6edf3rTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3okTb4b4b4) Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3connectedPort Tff7b72= Te6edf3connectPortTb4b4b4; Te6edf3rnode Tff7b72= Te6edf3rTb4b4b4; Tff7b72breakTb4b4b4; Tb4b4b4}
Tff7b72await Te6edf3rTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3attempt Tff7b72=== T79c0ff0Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffwaiting for device: Tffd700${Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3rnodeTb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'err.not_responding'Tb4b4b4)Tb4b4b4)Tb4b4b4;

Tff7b72const Te6edf3fwVer Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getFirmwareVersionTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffRNode detected β€” RNode_Firmware Tffd700${Te6edf3fwVerTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff93Tb4b4b4;

T8b949e// Check if already provisioned. This is the first real EEPROM
T8b949e// read right after a fresh post-flash reconnect β€” detect() and
T8b949e// getFirmwareVersion() above just succeeded so KISS is definitely
T8b949e// up, but the nRF52's LittleFS-backed "EEPROM" can still be
T8b949e// settling right after boot and occasionally miss the 3s default
T8b949e// timeout on this first larger read even though a retry moments
T8b949e// later succeeds instantly. Retry a couple of times instead of
T8b949e// failing the whole flash on one slow read.
Tff7b72let Te6edf3eeprom Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3attempt Tff7b72= T79c0ff0Tb4b4b4; Te6edf3attempt Tff7b72< T79c0ff3Tb4b4b4; Te6edf3attemptTff7b72++Tb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3eeprom Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72breakTb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3attempt Tff7b72=== T79c0ff2Tb4b4b4) Tff7b72throw Te6edf3eTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffEEPROM read slow to respond, retrying... (Tffd700${Te6edf3attempt Tff7b72+ T79c0ff1Tffd700}Ta5d6ff/3)Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff1000Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tff7b72const Te6edf3alreadyProvisioned Tff7b72= Te6edf3ROMTb4b4b4.Te6edf3isProvisionedTb4b4b4(Te6edf3eepromTb4b4b4)Tb4b4b4;

Tff7b72if Tb4b4b4(Tff7b72!Te6edf3alreadyProvisionedTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff`Ta5d6ffProvisioning EEPROM (Product: 0xTffd700${Te6edf3deviceTb4b4b4.Te6edf3product_idTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tffd700}Ta5d6ff, Model: 0xTffd700${Tb4b4b4(Te6edf3variantTb4b4b4.Te6edf3mapped_model_id Tff7b72?? Te6edf3variantTb4b4b4.Te6edf3model_idTb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tffd700}Ta5d6ff)...Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.provisioning'Tb4b4b4)Tb4b4b4;
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3provisionDeviceTb4b4b4(Te6edf3rnodeTb4b4b4, Te6edf3deviceTb4b4b4.Te6edf3product_idTb4b4b4, Te6edf3variantTb4b4b4.Te6edf3mapped_model_id Tff7b72?? Te6edf3variantTb4b4b4.Te6edf3model_idTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'EEPROM provisioned'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'EEPROM already provisioned, skipping...'Tb4b4b4)Tb4b4b4;
Tb4b4b4}

Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff97Tb4b4b4;

T8b949e// Reboot after provisioning so the hash is set on a stable device.
T8b949e// Both FDS (nRF52) and NVS (ESP32) can still be settling immediately
T8b949e// after provisioning, causing the hash write to fail or time out.
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Rebooting for hash write...'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.rebooting'Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3resetTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3rnode Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff5000Tb4b4b4)Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reconnecting to set firmware hash...'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.connecting'Tb4b4b4)Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3attempt Tff7b72= T79c0ff0Tb4b4b4; Te6edf3attempt Tff7b72< T79c0ff15Tb4b4b4; Te6edf3attemptTff7b72++Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3attempt Tff7b72> T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffnot ready, retrying... (Tffd700${Te6edf3attemptTffd700}Ta5d6ff/15)Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff2000Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72try Tb4b4b4{
Tff7b72let Te6edf3connectPort Tff7b72= Te6edf3portTb4b4b4;
Tff7b72const Te6edf3freshPorts Tff7b72= Tff7b72await Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4.Te6edf3getPortsTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3freshPortsTb4b4b4.Te6edf3length Tff7b72=== T79c0ff1Tb4b4b4) Te6edf3connectPort Tff7b72= Te6edf3freshPortsTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3r Tff7b72= Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3connectPortTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ok Tff7b72= Tff7b72await Te6edf3rTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3okTb4b4b4) Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3connectedPort Tff7b72= Te6edf3connectPortTb4b4b4; Te6edf3rnode Tff7b72= Te6edf3rTb4b4b4; Tff7b72breakTb4b4b4; Tb4b4b4}
Tff7b72await Te6edf3rTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3attempt Tff7b72=== T79c0ff0Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffwaiting for device: Tffd700${Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3rnodeTb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'err.no_response_reboot'Tb4b4b4)Tb4b4b4)Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Setting firmware hash...'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.hashing'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3fwHash Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getFirmwareHashTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setFirmwareHashTb4b4b4(Te6edf3fwHashTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff5000Tb4b4b4)Tb4b4b4; T8b949e// give FDS/NVS time to commit before reset
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Firmware hash set'Tb4b4b4)Tb4b4b4;

Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3resetTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff3000Tb4b4b4)Tb4b4b4;
Tb4b4b4}

Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff100Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Device is ready!'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.flashed'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3bootloaderWarned Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3trackFlashTb4b4b4(Te6edf3deviceTb4b4b4, Te6edf3variantTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3disconnectPortTb4b4b4(Tb4b4b4)Tb4b4b4;

Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3eTb4b4b4.Te6edf3isSoftStopTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'warn'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedPort Tff7b72= Tff7b72nullTb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3bootloaderWarned Tff7b72= Tff7b72falseTb4b4b4;
Te6edf3consoleTb4b4b4.Te6edf3errorTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3disconnectPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff0Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,

T8b949e// ── nRF52 flash via DFU ───────────────────────────────────
Tff7b72async Te6edf3doNrf52FlashTb4b4b4(Te6edf3portTb4b4b4, Te6edf3blobTb4b4b4, Te6edf3flashStep Tff7b72= Ta5d6ff'Flashing...'Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72typeof Te6edf3Nrf52DfuFlasher Tff7b72=== Ta5d6ff'undefined'Tb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'nrf52_dfu_flasher.js not loaded'Tb4b4b4)Tb4b4b4;

Tff7b72const Tb4b4b4{ Te6edf3usbVendorIdTb4b4b4, Te6edf3usbProductId Tb4b4b4} Tff7b72= Te6edf3portTb4b4b4.Te6edf3getInfoTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3vidStr Tff7b72= Te6edf3usbVendorId Tff7b72? Ta5d6ff`Ta5d6ff0xTffd700${Te6edf3usbVendorIdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff4Tb4b4b4,Ta5d6ff'0'Tb4b4b4)Tffd700}Ta5d6ff` Tff7b72: Ta5d6ff'unknown'Tb4b4b4;
Tff7b72const Te6edf3pidStr Tff7b72= Te6edf3usbProductId Tff7b72? Ta5d6ff`Ta5d6ff0xTffd700${Te6edf3usbProductIdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff4Tb4b4b4,Ta5d6ff'0'Tb4b4b4)Tffd700}Ta5d6ff` Tff7b72: Ta5d6ff'unknown'Tb4b4b4;

Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3bootloaderWarned Tff7b72&& Te6edf3usbVendorId Tff7b72=== T79c0ff0x239a Tff7b72&& Te6edf3usbProductId Tff7b72=== T79c0ff0x8029Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Ta5d6ff`Ta5d6ffDevice is in Meshtastic restore mode (VID Tffd700${Te6edf3vidStrTffd700}Ta5d6ff PID Tffd700${Te6edf3pidStrTffd700}Ta5d6ff)Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'warn.double_press_rst'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3bootloaderWarned Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72const Te6edf3e Tff7b72= Tff7b72new Tf85149ErrorTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'warn.double_press_rst'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Te6edf3eTb4b4b4.Te6edf3isSoftStop Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72throw Te6edf3eTb4b4b4;
Tb4b4b4}

T8b949e// The app and bootloader share the same USB VID on these boards (see
T8b949e// NRF52_VIDS), so matching the VID alone doesn't prove the device is
T8b949e// actually in DFU mode. KISS and the DFU transport's SLIP framing
T8b949e// both delimit frames with 0xC0, so blindly sending DFU packets at a
T8b949e// device that's still running the RNode app can occasionally get
T8b949e// back what looks like a few plausible ACKs (coincidental KISS
T8b949e// traffic) before desyncing β€” producing a misleading "bootloader
T8b949e// rejected the firmware" error instead of the real problem. Rule
T8b949e// this out with a quick, read-only KISS probe first β€” short timeout
T8b949e// since a real bootloader will just never answer it, and that's the
T8b949e// common case we don't want to slow down.
Tff7b72let Te6edf3stillRNode Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3rnode Tff7b72= Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Te6edf3stillRNode Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(T79c0ff800Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ T8b949e/* couldn't open/talk KISS to it at all β€” fine, proceed */ Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3stillRNodeTb4b4b4) Tb4b4b4{
T8b949e// Still running the RNode app, not the bootloader - this is the
T8b949e// common case when updating firmware on an already-flashed board.
T8b949e// Same 1200bps touch as the manual "Enter DFU Mode" tool; no need
T8b949e// to make the user do it by hand first.
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'Device is running RNode firmware, not in DFU/bootloader mode β€” entering DFU mode automatically...'Tb4b4b4)Tb4b4b4;
Te6edf3port Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3touchIntoNrf52DfuTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedPortTb4b4b4) Tff7b72thisTb4b4b4.Te6edf3disconnectPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}

Tff7b72const Tb4b4b4{ Te6edf3usbVendorIdTff7b72: Te6edf3dfuVidTb4b4b4, Te6edf3usbProductIdTff7b72: Te6edf3dfuPid Tb4b4b4} Tff7b72= Te6edf3portTb4b4b4.Te6edf3getInfoTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffAdafruit DFU bootloader (VID 0xTffd700${Te6edf3dfuVidTff7b72?Tb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff4Tb4b4b4,Ta5d6ff'0'Tb4b4b4) Tff7b72?? Ta5d6ff'unknown'Tffd700}Ta5d6ff PID 0xTffd700${Te6edf3dfuPidTff7b72?Tb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff4Tb4b4b4,Ta5d6ff'0'Tb4b4b4) Tff7b72?? Ta5d6ff'unknown'Tffd700}Ta5d6ff)Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Flashing firmware via DFU...'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Te6edf3flashStepTb4b4b4;

Tff7b72let Te6edf3lastPct Tff7b72= Tff7b72-T79c0ff1Tb4b4b4;
Tff7b72const Te6edf3onProgress Tff7b72= Tb4b4b4(Te6edf3pctTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff5 Tff7b72+ Tffa657MathTb4b4b4.Te6edf3roundTb4b4b4(Te6edf3pct Tff7b72* T79c0ff0.85Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3pct Tff7b72!== Te6edf3lastPctTb4b4b4) Tb4b4b4{
Te6edf3lastPct Tff7b72= Te6edf3pctTb4b4b4;
Tff7b72const Te6edf3filled Tff7b72= Tffa657MathTb4b4b4.Te6edf3floorTb4b4b4(Te6edf3pct Tff7b72/ T79c0ff5Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3bar Tff7b72= Ta5d6ff'β–ˆ'Tb4b4b4.Te6edf3repeatTb4b4b4(Te6edf3filledTb4b4b4) Tff7b72+ Ta5d6ff'β–‘'Tb4b4b4.Te6edf3repeatTb4b4b4(T79c0ff20 Tff7b72- Te6edf3filledTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3setProgressLineTb4b4b4(Ta5d6ff`Ta5d6ff[Tffd700${Te6edf3barTffd700}Ta5d6ff] Tffd700${Te6edf3pctTffd700}Ta5d6ff%Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4;

Tff7b72let Te6edf3flashed Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3attempt Tff7b72= T79c0ff0Tb4b4b4; Te6edf3attempt Tff7b72< T79c0ff3 Tff7b72&& Tff7b72!Te6edf3flashedTb4b4b4; Te6edf3attemptTff7b72++Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3attempt Tff7b72> T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3progressLineIdx Tff7b72= Tff7b72-T79c0ff1Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffPort not ready, retrying in 1 s... (Tffd700${Te6edf3attempt Tff7b72+ T79c0ff1Tffd700}Ta5d6ff/3)Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff1000Tb4b4b4)Tb4b4b4;
Te6edf3lastPct Tff7b72= Tff7b72-T79c0ff1Tb4b4b4;
Tb4b4b4}
Tff7b72try Tb4b4b4{
Tff7b72await Tff7b72new Te6edf3Nrf52DfuFlasherTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4.Te6edf3flashTb4b4b4(Te6edf3blobTb4b4b4, Te6edf3onProgressTb4b4b4)Tb4b4b4;
Te6edf3flashed Tff7b72= Tff7b72trueTb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3attempt Tff7b72< T79c0ff2 Tff7b72&& Ta5d6ff/writable/iTb4b4b4.Te6edf3testTb4b4b4(Tffa657StringTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4) Tff7b72continueTb4b4b4;
T8b949e// sendPacket() now reads back and validates the bootloader's ACK
T8b949e// for every packet (see nrf52_dfu_flasher.js), so these phases mean
T8b949e// different things: 'start' failing means the device never ACKed
T8b949e// the very first packet at all β€” it almost certainly isn't in DFU
T8b949e// mode. 'init'/'data' failing means it WAS talking fine and then
T8b949e// stopped acking or rejected something mid-transfer β€” in practice
T8b949e// that's most often a SoftDevice/DFU-compatibility mismatch
T8b949e// (sd-req) baked into how the firmware zip was packaged, not a bad
T8b949e// cable or board.
Tff7b72if Tb4b4b4(Te6edf3eTb4b4b4.Te6edf3dfuPhase Tff7b72=== Ta5d6ff'start'Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3hint Tff7b72= Tff7b72new Tf85149ErrorTb4b4b4(
Ta5d6ff`Ta5d6ffDevice never acknowledged the DFU start packet (Tffd700${Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTffd700}Ta5d6ff). Ta5d6ff` Tff7b72+
Ta5d6ff`Ta5d6ffIt's likely not actually in DFU/bootloader mode β€” use the "Enter DFU Mode" Ta5d6ff` Tff7b72+
Ta5d6ff`Ta5d6ffadvanced tool (or double-press RST) and try again.Ta5d6ff`
Tb4b4b4)Tb4b4b4;
Te6edf3hintTb4b4b4.Te6edf3cause Tff7b72= Te6edf3eTb4b4b4;
Tff7b72throw Te6edf3hintTb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3eTb4b4b4.Te6edf3dfuPhase Tff7b72=== Ta5d6ff'init' Tff7b72|| Te6edf3eTb4b4b4.Te6edf3dfuPhase Tff7b72=== Ta5d6ff'data'Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3hint Tff7b72= Tff7b72new Tf85149ErrorTb4b4b4(
Ta5d6ff`Ta5d6ffBootloader stopped acknowledging packets during firmware transfer (Tffd700${Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTffd700}Ta5d6ff). Ta5d6ff` Tff7b72+
Ta5d6ff`Ta5d6ffThis usually means it rejected the firmware package rather than a Ta5d6ff` Tff7b72+
Ta5d6ff`Ta5d6ffconnection problem β€” most often a SoftDevice/DFU compatibility mismatch Ta5d6ff` Tff7b72+
Ta5d6ff`Ta5d6ff(sd-req) in how this firmware build was packaged.Ta5d6ff`
Tb4b4b4)Tb4b4b4;
Te6edf3hintTb4b4b4.Te6edf3cause Tff7b72= Te6edf3eTb4b4b4;
Tff7b72throw Te6edf3hintTb4b4b4;
Tb4b4b4}
Tff7b72throw Te6edf3eTb4b4b4;
Tb4b4b4}
Tb4b4b4}

Tff7b72thisTb4b4b4.Te6edf3progressLineIdx Tff7b72= Tff7b72-T79c0ff1Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'DFU transfer complete, device rebooting...'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── esptool connection ────────────────────────────────────
T8b949e// Releases the Web Serial locks esptool-js holds and closes the port,
T8b949e// so the port can be re-opened by a retry (or handed back to the OS).
Tff7b72async Te6edf3releaseEspTransportTb4b4b4(Te6edf3transportTb4b4b4, Te6edf3portTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3transportTff7b72?Tb4b4b4.Te6edf3readerTb4b4b4) Tb4b4b4{
Tff7b72await Te6edf3transportTb4b4b4.Te6edf3readerTb4b4b4.Te6edf3cancelTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3transportTb4b4b4.Te6edf3readerTb4b4b4.Te6edf3releaseLockTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3transportTff7b72?Tb4b4b4.Te6edf3writerTb4b4b4) Te6edf3transportTb4b4b4.Te6edf3writerTb4b4b4.Te6edf3releaseLockTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4}Tb4b4b4,

T8b949e// True for the failures that mean "the link itself is bad", as opposed
T8b949e// to "no device answered". Only these are worth retrying slower.
Te6edf3isEspLinkNoiseErrorTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3msg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTff7b72?Tb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tff7b72return Ta5d6ff/invalid head of packet|serial noise|verify flash chip connection|timed out waiting for packet/iTb4b4b4.Te6edf3testTb4b4b4(Te6edf3msgTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// Connects esptool-js to an ESP32 in download mode, working down
T8b949e// ESP_BAUD_LADDER until the link holds.
T8b949e//
T8b949e// Once the stub is up, esptool-js raises the speed by closing and
T8b949e// re-opening the serial port (ESPLoader.changeBaud). A Linux tty
T8b949e// discards anything still in flight across that close; the Windows
T8b949e// CP210x driver (SiLabs 11.x) hands those stale bytes to the next
T8b949e// read instead. esptool-js then sees them as the start of the reply
T8b949e// to its first post-switch command and gives up with
T8b949e// Invalid head of packet (0x80): Possible serial noise or corruption
T8b949e// surfaced as "Unable to verify flash chip connection", right after
T8b949e// it logged "Changed". That is why this only ever bites on Windows.
T8b949e//
T8b949e// Guard 1: drop whatever the driver buffered across a baud switch
T8b949e// before the first command goes out at the new speed. Guard 2: if the
T8b949e// link still doesn't come up, reconnect from scratch one speed lower β€”
T8b949e// 921600 is simply out of reach for some CP2102 + ESP32-D0WD boards
T8b949e// (DIY-V1) on Windows, no matter how clean the handover is.
Tff7b72async Te6edf3espConnectTb4b4b4(Te6edf3portTb4b4b4, Te6edf3onLineTb4b4b4) Tb4b4b4{
T8b949e// Resume at the speed that worked last time and keep stepping down
T8b949e// from there β€” never back up to one already known to be too fast.
Tff7b72const Te6edf3start Tff7b72= Tffa657MathTb4b4b4.Te6edf3maxTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3ESP_BAUD_LADDERTb4b4b4.Te6edf3indexOfTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3espBaudrateTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ladder Tff7b72= Te6edf3ESP_BAUD_LADDERTb4b4b4.Te6edf3sliceTb4b4b4(Te6edf3startTb4b4b4)Tb4b4b4;

Tff7b72let Te6edf3lastErrTb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3i Tff7b72= T79c0ff0Tb4b4b4; Te6edf3i Tff7b72< Te6edf3ladderTb4b4b4.Te6edf3lengthTb4b4b4; Te6edf3iTff7b72++Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3baudrate Tff7b72= Te6edf3ladderTb4b4b4[Te6edf3iTb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3transport Tff7b72= Tff7b72new Tffa657windowTb4b4b4.Te6edf3TransportTb4b4b4(Te6edf3portTb4b4b4, Tff7b72falseTb4b4b4)Tb4b4b4;
Te6edf3transportTb4b4b4.Te6edf3trace Tff7b72= Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{Tb4b4b4}Tb4b4b4;
Tff7b72const Te6edf3esploader Tff7b72= Tff7b72new Tffa657windowTb4b4b4.Te6edf3ESPLoaderTb4b4b4(Tb4b4b4{
Te6edf3transportTb4b4b4, Te6edf3baudrateTb4b4b4, Te6edf3debugLoggingTff7b72: Tff7b72falseTb4b4b4, Te6edf3enableTracingTff7b72: Tff7b72falseTb4b4b4,
Te6edf3terminalTff7b72: Tb4b4b4{
Te6edf3cleanTb4b4b4(Tb4b4b4) Tb4b4b4{Tb4b4b4}Tb4b4b4,
Te6edf3writeLineTff7b72: Tb4b4b4(Te6edf3dTb4b4b4) Tb4b4b4=> Tb4b4b4{ Tff7b72if Tb4b4b4(Te6edf3dTff7b72?Tb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3onLineTb4b4b4(Te6edf3dTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4; Tb4b4b4}Tb4b4b4,
Te6edf3writeTb4b4b4(Tb4b4b4) Tb4b4b4{Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;

Tff7b72const Te6edf3changeBaud Tff7b72= Te6edf3esploaderTb4b4b4.Te6edf3changeBaudTb4b4b4.Te6edf3bindTb4b4b4(Te6edf3esploaderTb4b4b4)Tb4b4b4;
Te6edf3esploaderTb4b4b4.Te6edf3changeBaud Tff7b72= Tff7b72async Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72await Te6edf3changeBaudTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(Te6edf3ESP_BAUD_SETTLE_MSTb4b4b4)Tb4b4b4;
Te6edf3transportTb4b4b4.Te6edf3flushInputTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4;

Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3chip Tff7b72= Tff7b72await Te6edf3esploaderTb4b4b4.Te6edf3mainTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3espBaudrate Tff7b72= Te6edf3baudrateTb4b4b4;
Tff7b72return Tb4b4b4{ Te6edf3transportTb4b4b4, Te6edf3esploaderTb4b4b4, Te6edf3chip Tb4b4b4}Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Te6edf3lastErr Tff7b72= Te6edf3eTb4b4b4;
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3releaseEspTransportTb4b4b4(Te6edf3transportTb4b4b4, Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3next Tff7b72= Te6edf3ladderTb4b4b4[Te6edf3i Tff7b72+ T79c0ff1Tb4b4b4]Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3next Tff7b72=== Tff7b72undefined Tff7b72|| Tff7b72!Tff7b72thisTb4b4b4.Te6edf3isEspLinkNoiseErrorTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4) Tff7b72throw Te6edf3eTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Ta5d6ff`Ta5d6ffSerial link unstable at Tffd700${Te6edf3baudrateTffd700}Ta5d6ff baud β€” reconnecting at Tffd700${Te6edf3nextTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff500Tb4b4b4)Tb4b4b4; T8b949e// Windows needs a moment to release the port
Tb4b4b4}
Tb4b4b4}
Tff7b72throw Te6edf3lastErrTb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── ESP32 flash via esptool-js ────────────────────────────
Tff7b72async Te6edf3doEsp32FlashTb4b4b4(Te6edf3portTb4b4b4, Te6edf3blobTb4b4b4, Te6edf3flashConfigTb4b4b4, Te6edf3flashStep Tff7b72= Ta5d6ff'Flashing...'Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tffa657windowTb4b4b4.Te6edf3ESPLoaderTb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'esptool-js not loaded'Tb4b4b4)Tb4b4b4;

T8b949e// Unzip
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reading firmware archive...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3blobReader Tff7b72= Tff7b72new Tffa657windowTb4b4b4.Te6edf3zipTb4b4b4.Te6edf3BlobReaderTb4b4b4(Te6edf3blobTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3zipReader Tff7b72= Tff7b72new Tffa657windowTb4b4b4.Te6edf3zipTb4b4b4.Te6edf3ZipReaderTb4b4b4(Te6edf3blobReaderTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3entries Tff7b72= Tff7b72await Te6edf3zipReaderTb4b4b4.Te6edf3getEntriesTb4b4b4(Tb4b4b4)Tb4b4b4;

Tff7b72const Te6edf3filesToFlash Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3fileNames Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Tb4b4b4[Te6edf3addrTb4b4b4, Te6edf3fnameTb4b4b4] Tff7b72of Tffa657ObjectTb4b4b4.Te6edf3entriesTb4b4b4(Te6edf3flashConfigTb4b4b4.Te6edf3flash_filesTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72let Te6edf3entry Tff7b72= Te6edf3entriesTb4b4b4.Te6edf3findTb4b4b4(Te6edf3e Tb4b4b4=> Te6edf3eTb4b4b4.Te6edf3filename Tff7b72=== Te6edf3fnameTb4b4b4)Tb4b4b4;
T8b949e// Some firmware zips now ship the RNode console image with a
T8b949e// per-device suffix (e.g. console_image_meshpoe_s3.bin) instead of
T8b949e// the plain console_image.bin. Fall back to matching any
T8b949e// console_image*.bin so every variant keeps flashing.
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3entry Tff7b72&& Te6edf3fname Tff7b72=== Ta5d6ff'console_image.bin'Tb4b4b4) Tb4b4b4{
Te6edf3entry Tff7b72= Te6edf3entriesTb4b4b4.Te6edf3findTb4b4b4(Te6edf3e Tb4b4b4=> Tff7b72/Tff7b72^Te6edf3console_imageTb4b4b4.Tff7b72*\Tb4b4b4.Te6edf3bin$Tff7b72/Te6edf3iTb4b4b4.Te6edf3testTb4b4b4(Te6edf3eTb4b4b4.Te6edf3filenameTb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3entryTb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff`Tffd700${Te6edf3fnameTffd700}Ta5d6ff not found in firmware zipTa5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3fileBlob Tff7b72= Tff7b72await Te6edf3entryTb4b4b4.Te6edf3getDataTb4b4b4(Tff7b72new Tffa657windowTb4b4b4.Te6edf3zipTb4b4b4.Te6edf3BlobWriterTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3data Tff7b72= Tff7b72new Tffa657Uint8ArrayTb4b4b4(Tff7b72await Te6edf3fileBlobTb4b4b4.Te6edf3arrayBufferTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4;
Te6edf3filesToFlashTb4b4b4.Te6edf3pushTb4b4b4(Tb4b4b4{ Te6edf3addressTff7b72: Tffa657parseIntTb4b4b4(Te6edf3addrTb4b4b4)Tb4b4b4, Te6edf3data Tb4b4b4}Tb4b4b4)Tb4b4b4;
Te6edf3fileNamesTb4b4b4.Te6edf3pushTb4b4b4(Tb4b4b4{ Te6edf3addrTb4b4b4, Te6edf3fname Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Tffd700${Te6edf3filesToFlashTb4b4b4.Te6edf3lengthTffd700}Ta5d6ff partition(s) readyTa5d6ff`Tb4b4b4)Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Connecting to chip...'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.connecting'Tb4b4b4)Tb4b4b4;

Tff7b72let Te6edf3transportTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72let Te6edf3esploaderTb4b4b4, Te6edf3chipTb4b4b4;
Tb4b4b4(Tb4b4b4{ Te6edf3transportTb4b4b4, Te6edf3esploaderTb4b4b4, Te6edf3chip Tb4b4b4} Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3espConnectTb4b4b4(
Te6edf3portTb4b4b4, Tb4b4b4(Te6edf3lineTb4b4b4) Tb4b4b4=> Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Te6edf3lineTb4b4b4)
Tb4b4b4)Tb4b4b4)Tb4b4b4;

Tff7b72let Te6edf3writeFileIdx Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3esploaderTb4b4b4.Te6edf3terminalTb4b4b4.Te6edf3writeLine Tff7b72= Tb4b4b4(Te6edf3dTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3d Tff7b72|| Tff7b72!Te6edf3dTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72const Te6edf3line Tff7b72= Te6edf3dTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3lineTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'Writing at'Tb4b4b4)Tb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3lineTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff'Compressed 'Tb4b4b4) Tff7b72&& Te6edf3writeFileIdx Tff7b72< Te6edf3fileNamesTb4b4b4.Te6edf3lengthTb4b4b4) Tb4b4b4{
Tff7b72const Tb4b4b4{ Te6edf3addrTb4b4b4, Te6edf3fname Tb4b4b4} Tff7b72= Te6edf3fileNamesTb4b4b4[Te6edf3writeFileIdxTff7b72++Tb4b4b4]Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff`Tffd700${Te6edf3fnameTffd700}Ta5d6ff @ Tffd700${Te6edf3addrTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Te6edf3lineTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffChip: Tffd700${Te6edf3chipTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff`Ta5d6ffFlashing firmware (Tffd700${Te6edf3flashConfigTb4b4b4.Te6edf3flash_sizeTffd700}Ta5d6ff)...Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Te6edf3flashStepTb4b4b4;

Tff7b72let Te6edf3lastPct Tff7b72= T79c0ff0Tb4b4b4;
Tff7b72let Te6edf3lastFileIdx Tff7b72= Tff7b72-T79c0ff1Tb4b4b4;
Tff7b72await Te6edf3esploaderTb4b4b4.Te6edf3writeFlashTb4b4b4(Tb4b4b4{
Te6edf3fileArrayTff7b72: Te6edf3filesToFlashTb4b4b4,
Te6edf3flashSizeTff7b72: Te6edf3flashConfigTb4b4b4.Te6edf3flash_sizeTb4b4b4,
Te6edf3flashModeTff7b72: Ta5d6ff'dio'Tb4b4b4,
Te6edf3flashFreqTff7b72: Ta5d6ff'80m'Tb4b4b4,
Te6edf3eraseAllTff7b72: Tff7b72falseTb4b4b4,
Te6edf3compressTff7b72: Tff7b72trueTb4b4b4,
Te6edf3calculateMD5HashTff7b72: Tb4b4b4(Te6edf3imgTb4b4b4) Tb4b4b4=> Te6edf3CryptoJSTb4b4b4.Te6edf3MD5Tb4b4b4(Te6edf3CryptoJSTb4b4b4.Te6edf3encTb4b4b4.Te6edf3HexTb4b4b4.Te6edf3parseTb4b4b4(Te6edf3UtilsTb4b4b4.Te6edf3bytesToHexTb4b4b4(Te6edf3imgTb4b4b4)Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3reportProgressTff7b72: Tb4b4b4(Te6edf3fileIdxTb4b4b4, Te6edf3writtenTb4b4b4, Te6edf3totalTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3fileIdx Tff7b72!== Te6edf3lastFileIdxTb4b4b4) Tb4b4b4{
Te6edf3lastFileIdx Tff7b72= Te6edf3fileIdxTb4b4b4;
Te6edf3lastPct Tff7b72= Tff7b72-T79c0ff1Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3progressLineIdx Tff7b72= Tff7b72-T79c0ff1Tb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3pct Tff7b72= Tffa657MathTb4b4b4.Te6edf3floorTb4b4b4(Tb4b4b4(Te6edf3written Tff7b72/ Te6edf3totalTb4b4b4) Tff7b72* T79c0ff100Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3pct Tff7b72!== Te6edf3lastPctTb4b4b4) Tb4b4b4{
Te6edf3lastPct Tff7b72= Te6edf3pctTb4b4b4;
Tff7b72const Te6edf3filled Tff7b72= Tffa657MathTb4b4b4.Te6edf3floorTb4b4b4(Te6edf3pct Tff7b72/ T79c0ff5Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3bar Tff7b72= Ta5d6ff'β–ˆ'Tb4b4b4.Te6edf3repeatTb4b4b4(Te6edf3filledTb4b4b4) Tff7b72+ Ta5d6ff'β–‘'Tb4b4b4.Te6edf3repeatTb4b4b4(T79c0ff20 Tff7b72- Te6edf3filledTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3setProgressLineTb4b4b4(Ta5d6ff`Ta5d6ff[Tffd700${Te6edf3barTffd700}Ta5d6ff] Tffd700${Te6edf3pctTffd700}Ta5d6ff% (Tffd700${Te6edf3fileIdx Tff7b72+ T79c0ff1Tffd700}Ta5d6ff/Tffd700${Te6edf3filesToFlashTb4b4b4.Te6edf3lengthTffd700}Ta5d6ff)Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff5 Tff7b72+ Tffa657MathTb4b4b4.Te6edf3floorTb4b4b4(Tb4b4b4(Te6edf3pct Tff7b72/ T79c0ff100Tb4b4b4) Tff7b72* T79c0ff82Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3progressLineIdx Tff7b72= Tff7b72-T79c0ff1Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Firmware flashed'Tb4b4b4)Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Resetting device...'Tb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3flashFinishOk Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3esploaderTb4b4b4.Te6edf3chipTff7b72?Tb4b4b4.Te6edf3CHIP_NAME Tff7b72=== Ta5d6ff'ESP32-S3'Tb4b4b4) Tb4b4b4{
T8b949e// ESP32-S3 ROM bug: USB Serial/JTAG reset loops back into download mode
T8b949e// because strapping pins are not re-sampled on that reset type.
T8b949e// Fix: use RTC WDT reset, which IS one of the reset types that re-samples
T8b949e// strapping pins (GPIO0 released β†’ normal boot). Matches esptool's
T8b949e// --after watchdog-reset. See: https://github.com/espressif/esp-idf/issues/13287
Tff7b72try Tb4b4b4{
Tff7b72await Te6edf3esploaderTb4b4b4.Te6edf3writeRegTb4b4b4(T79c0ff0x60008128Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4; T8b949e// RTC_CNTL_OPTION1_REG: clear force-download-boot
Tff7b72await Te6edf3esploaderTb4b4b4.Te6edf3writeRegTb4b4b4(T79c0ff0x600080B0Tb4b4b4, T79c0ff0x50D83AA1Tb4b4b4)Tb4b4b4; T8b949e// RTC_CNTL_WDTWPROTECT_REG: unlock
Tff7b72await Te6edf3esploaderTb4b4b4.Te6edf3writeRegTb4b4b4(T79c0ff0x6000809CTb4b4b4, T79c0ff2000Tb4b4b4)Tb4b4b4; T8b949e// RTC_CNTL_WDTCONFIG1_REG: timeout
Tff7b72await Te6edf3esploaderTb4b4b4.Te6edf3writeRegTb4b4b4(T79c0ff0x60008098Tb4b4b4, Tb4b4b4(T79c0ff1Tff7b72<<T79c0ff31Tb4b4b4)Tff7b72|Tb4b4b4(T79c0ff5Tff7b72<<T79c0ff28Tb4b4b4)Tff7b72|Tb4b4b4(T79c0ff1Tff7b72<<T79c0ff8Tb4b4b4)Tff7b72|T79c0ff2Tb4b4b4)Tb4b4b4; T8b949e// RTC_CNTL_WDTCONFIG0_REG: enable
Tff7b72await Te6edf3esploaderTb4b4b4.Te6edf3writeRegTb4b4b4(T79c0ff0x600080B0Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4; T8b949e// RTC_CNTL_WDTWPROTECT_REG: lock
Te6edf3flashFinishOk Tff7b72= Tff7b72trueTb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72await Te6edf3esploaderTb4b4b4.Te6edf3flashFinishTb4b4b4(Tff7b72trueTb4b4b4)Tb4b4b4;
Te6edf3flashFinishOk Tff7b72= Tff7b72trueTb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
T8b949e// USB drops during reset β€” normal for native USB devices.
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3flashFinishOkTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Reset command sent'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'warn.press_rst_boot'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4}

Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3releaseEspTransportTb4b4b4(Te6edf3transportTb4b4b4, Te6edf3portTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,

T8b949e// ── EEPROM provisioning ───────────────────────────────────
Tff7b72async Te6edf3provisionDeviceTb4b4b4(Te6edf3rnodeTb4b4b4, Te6edf3productIdTb4b4b4, Te6edf3modelIdTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3hwRev Tff7b72= T79c0ff0x01Tb4b4b4;
Tff7b72const Te6edf3serial Tff7b72= T79c0ff1Tb4b4b4;
Tff7b72const Te6edf3ts Tff7b72= Tffa657MathTb4b4b4.Te6edf3floorTb4b4b4(Tffa657DateTb4b4b4.Te6edf3nowTb4b4b4(Tb4b4b4) Tff7b72/ T79c0ff1000Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3serialBytes Tff7b72= Te6edf3UtilsTb4b4b4.Te6edf3packUInt32BETb4b4b4(Te6edf3serialTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3tsBytes Tff7b72= Te6edf3UtilsTb4b4b4.Te6edf3packUInt32BETb4b4b4(Te6edf3tsTb4b4b4)Tb4b4b4;

Tff7b72const Te6edf3checksum Tff7b72= Te6edf3UtilsTb4b4b4.Te6edf3md5Tb4b4b4(Tb4b4b4[
Te6edf3productIdTb4b4b4, Te6edf3modelIdTb4b4b4, Te6edf3hwRevTb4b4b4,
Tb4b4b4...Tffa657ArrayTb4b4b4.Tff7b72fromTb4b4b4(Te6edf3serialBytesTb4b4b4)Tb4b4b4,
Tb4b4b4...Tffa657ArrayTb4b4b4.Tff7b72fromTb4b4b4(Te6edf3tsBytesTb4b4b4)Tb4b4b4,
Tb4b4b4]Tb4b4b4)Tb4b4b4;

T8b949e// Write device info. After each write (or small group) we read the ROM
T8b949e// back with a 30 s timeout β€” the roundtrip waits for the device to
T8b949e// finish any pending FDS flash operation before the next write is sent.
T8b949e// This matches the old flasher's pacing, which has no timeout at all on
T8b949e// ROM reads and therefore never races ahead of the device's write queue.
Tff7b72const Te6edf3romRead Tff7b72= Tb4b4b4(Tb4b4b4) Tb4b4b4=> Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(T79c0ff30000Tb4b4b4)Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffproduct=0xTffd700${Te6edf3productIdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tffd700}Ta5d6ff model=0xTffd700${Te6edf3modelIdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tffd700}Ta5d6ff hw_rev=0xTffd700${Te6edf3hwRevTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3writeRomTb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3ADDR_PRODUCTTb4b4b4, Te6edf3productIdTb4b4b4)Tb4b4b4; Tff7b72await Te6edf3romReadTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3writeRomTb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3ADDR_MODELTb4b4b4, Te6edf3modelIdTb4b4b4)Tb4b4b4; Tff7b72await Te6edf3romReadTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3writeRomTb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3ADDR_HW_REVTb4b4b4, Te6edf3hwRevTb4b4b4)Tb4b4b4; Tff7b72await Te6edf3romReadTb4b4b4(Tb4b4b4)Tb4b4b4;

Tff7b72for Tb4b4b4(Tff7b72let Te6edf3i Tff7b72= T79c0ff0Tb4b4b4; Te6edf3i Tff7b72< T79c0ff4Tb4b4b4; Te6edf3iTff7b72++Tb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3writeRomTb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3ADDR_SERIAL Tff7b72+ Te6edf3iTb4b4b4, Te6edf3serialBytesTb4b4b4[Te6edf3iTb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3romReadTb4b4b4(Tb4b4b4)Tb4b4b4;

Tff7b72for Tb4b4b4(Tff7b72let Te6edf3i Tff7b72= T79c0ff0Tb4b4b4; Te6edf3i Tff7b72< T79c0ff4Tb4b4b4; Te6edf3iTff7b72++Tb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3writeRomTb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3ADDR_MADE Tff7b72+ Te6edf3iTb4b4b4, Te6edf3tsBytesTb4b4b4[Te6edf3iTb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3romReadTb4b4b4(Tb4b4b4)Tb4b4b4;

T8b949e// Write checksum
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3i Tff7b72= T79c0ff0Tb4b4b4; Te6edf3i Tff7b72< T79c0ff16Tb4b4b4; Te6edf3iTff7b72++Tb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3writeRomTb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3ADDR_CHKSUM Tff7b72+ Te6edf3iTb4b4b4, Te6edf3checksumTb4b4b4[Te6edf3iTb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3romReadTb4b4b4(Tb4b4b4)Tb4b4b4;

T8b949e// Write blank signature
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3i Tff7b72= T79c0ff0Tb4b4b4; Te6edf3i Tff7b72< T79c0ff128Tb4b4b4; Te6edf3iTff7b72++Tb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3writeRomTb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3ADDR_SIGNATURE Tff7b72+ Te6edf3iTb4b4b4, T79c0ff0x00Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3romReadTb4b4b4(Tb4b4b4)Tb4b4b4;

T8b949e// Write info lock byte
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3writeRomTb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3ADDR_INFO_LOCKTb4b4b4, Te6edf3ROMTb4b4b4.Te6edf3INFO_LOCK_BYTETb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3romReadTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Bootloader entry via DTR/RTS ──────────────────────────
Tff7b72async Te6edf3enterBootloaderTb4b4b4(Te6edf3portTb4b4b4) Tb4b4b4{
T8b949e// Try to open the port and send the classic reset sequence.
T8b949e// On Linux with cdc_acm-claimed USB JTAG devices this may fail β€”
T8b949e// in that case we just wait and let the user retry manually.
Tff7b72let Te6edf3opened Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72await Te6edf3portTb4b4b4.Te6edf3openTb4b4b4(Tb4b4b4{ Te6edf3baudRateTff7b72: T79c0ff115200 Tb4b4b4}Tb4b4b4)Tb4b4b4;
Te6edf3opened Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72await Te6edf3portTb4b4b4.Te6edf3setSignalsTb4b4b4(Tb4b4b4{ Te6edf3dataTerminalReadyTff7b72: Tff7b72falseTb4b4b4, Te6edf3requestToSendTff7b72: Tff7b72false Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff50Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3portTb4b4b4.Te6edf3setSignalsTb4b4b4(Tb4b4b4{ Te6edf3dataTerminalReadyTff7b72: Tff7b72falseTb4b4b4, Te6edf3requestToSendTff7b72: Tff7b72true Tb4b4b4}Tb4b4b4)Tb4b4b4; T8b949e// EN low
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff100Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3portTb4b4b4.Te6edf3setSignalsTb4b4b4(Tb4b4b4{ Te6edf3dataTerminalReadyTff7b72: Tff7b72trueTb4b4b4, Te6edf3requestToSendTff7b72: Tff7b72false Tb4b4b4}Tb4b4b4)Tb4b4b4; T8b949e// GPIO0 low + EN high
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff50Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3portTb4b4b4.Te6edf3setSignalsTb4b4b4(Tb4b4b4{ Te6edf3dataTerminalReadyTff7b72: Tff7b72falseTb4b4b4, Te6edf3requestToSendTff7b72: Tff7b72false Tb4b4b4}Tb4b4b4)Tb4b4b4; T8b949e// release
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'bootloader reset signal sent'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3openedTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'warn.no_port_signal'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'warn.manual_bootloader'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3openedTb4b4b4) Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'waiting for device to re-enumerate...'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff2500Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Advanced tools ────────────────────────────────────────
T8b949e// Sends a "1200bps touch" (open the serial port at 1200 baud, then
T8b949e// close it) to force an nRF52 board straight into its DFU bootloader.
T8b949e// Boards built on the Adafruit nRF52 Arduino core (ProMicro/nice!nano/
T8b949e// FakeTec, T-Echo, RAK4631, Heltec T114...) watch for this on their CDC
T8b949e// serial port and reset into DFU on their own β€” this replaces the
T8b949e// manual double-press-RST dance, which is a tight timing window that's
T8b949e// easy to miss on these small boards (same technique meshcore.co.uk's
T8b949e// web flasher uses). Nrf52DfuFlasher.enterDfuMode() already implemented
T8b949e// this; it just wasn't wired up to anything yet.
T8b949e// Sends the 1200bps DFU touch and verifies the device no longer answers
T8b949e// as RNode afterward, returning the (possibly re-enumerated) port to use
T8b949e// for DFU flashing. Shared by the manual "Enter DFU Mode" tool and
T8b949e// doNrf52Flash()'s automatic fallback when it finds a connected board
T8b949e// still running RNode firmware instead of the bootloader.
Tff7b72async Te6edf3touchIntoNrf52DfuTb4b4b4(Te6edf3portTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Sending 1200bps touch to enter DFU mode...'Tb4b4b4)Tb4b4b4;
Tff7b72await Tff7b72new Te6edf3Nrf52DfuFlasherTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4.Te6edf3enterDfuModeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'Touch sent β€” device should have reset into the bootloader, verifying...'Tb4b4b4)Tb4b4b4;

T8b949e// Verify *only* by checking whether the device still answers as
T8b949e// RNode over KISS β€” never by sending it a real DFU protocol packet.
T8b949e// An earlier version of this check sent a "harmless" zero-size DFU
T8b949e// START packet as a positive confirmation, but then closed the port
T8b949e// without ever finishing that transaction (no INIT/DATA/STOP) β€”
T8b949e// that's a real, incomplete handshake with the bootloader's DFU
T8b949e// state machine, and on one board it left the bootloader itself
T8b949e// unresponsive over USB afterwards. Not worth the risk: this can
T8b949e// only prove "the app is gone", not "this is definitely a DFU
T8b949e// bootloader", but that's a trade worth making.
T8b949e//
T8b949e// Try the same port object first (works if the browser keeps it
T8b949e// valid across the device's re-enumeration); if that fails to even
T8b949e// open, fall back to scanning granted ports for a matching-VID
T8b949e// candidate.
Tff7b72let Te6edf3stillRNode Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72let Te6edf3checkedPort Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72let Te6edf3dfuPort Tff7b72= Te6edf3portTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3rnode Tff7b72= Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Te6edf3stillRNode Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3checkedPort Tff7b72= Tff7b72trueTb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffCould not reopen original port (Tffd700${Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTffd700}Ta5d6ff) β€” scanning for the re-enumerated device...Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3freshPorts Tff7b72= Tff7b72await Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4.Te6edf3getPortsTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3candidates Tff7b72= Te6edf3freshPortsTb4b4b4.Te6edf3filterTb4b4b4(Te6edf3p Tb4b4b4=> Te6edf3NRF52_VIDSTb4b4b4.Te6edf3includesTb4b4b4(Te6edf3pTb4b4b4.Te6edf3getInfoTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3usbVendorIdTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Tffd700${Te6edf3candidatesTb4b4b4.Te6edf3lengthTffd700}Ta5d6ff matching-VID port(s) foundTa5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3p Tff7b72of Te6edf3candidatesTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3rnode Tff7b72= Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3pTb4b4b4)Tb4b4b4;
Te6edf3stillRNode Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3checkedPort Tff7b72= Tff7b72trueTb4b4b4;
Te6edf3dfuPort Tff7b72= Te6edf3pTb4b4b4;
Tff7b72breakTb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3e2Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffCandidate port check failed: Tffd700${Te6edf3e2Tb4b4b4.Te6edf3message Tff7b72|| Te6edf3e2Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72if Tb4b4b4(Te6edf3stillRNodeTb4b4b4) Tb4b4b4{
Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'Device still answers as RNode over KISS β€” the touch did not actually reset it into the bootloader'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3checkedPortTb4b4b4) Tb4b4b4{
Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'Could not reach the device on any known port after the touch'Tb4b4b4)Tb4b4b4;
Tb4b4b4}

Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Device no longer answers as RNode β€” should be in DFU mode now'Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3dfuPortTb4b4b4;
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3enterNrf52DfuTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4) Tb4b4b4{ Te6edf3alertTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'alert.no_serial'Tb4b4b4)Tb4b4b4)Tb4b4b4; Tff7b72returnTb4b4b4; Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72typeof Te6edf3Nrf52DfuFlasher Tff7b72=== Ta5d6ff'undefined'Tb4b4b4) Tb4b4b4{ Te6edf3alertTb4b4b4(Ta5d6ff'nrf52_dfu_flasher.js not loaded'Tb4b4b4)Tb4b4b4; Tff7b72returnTb4b4b4; Tb4b4b4}

Tff7b72let Te6edf3portTb4b4b4;
Tff7b72try Tb4b4b4{
Te6edf3port Tff7b72= Tff7b72await Te6edf3navigatorTb4b4b4.Te6edf3serialTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4{ Te6edf3filtersTff7b72: Tb4b4b4[Tb4b4b4] Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72returnTb4b4b4; T8b949e// user cancelled
Tb4b4b4}

Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3clearLogTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.dfu_touch'Tb4b4b4)Tb4b4b4;

Tff7b72try Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3touchIntoNrf52DfuTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.dfu_ready'Tb4b4b4)Tb4b4b4;
T8b949e// Device just reset and re-enumerated as a new USB device β€” any
T8b949e// cached port/connection from before is now stale.
Tff7b72thisTb4b4b4.Te6edf3disconnectPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,

T8b949e// Erases the connected board's flash. Branches by platform: nRF52
T8b949e// boards don't support a raw esptool-style chip erase over DFU, so
T8b949e// instead this puts the board in bootloader mode and flashes the
T8b949e// universal eraser app (NRF52_ERASER_ZIP), which wipes the internal
T8b949e// filesystem/settings partition and reboots back into the bootloader.
Tff7b72async Te6edf3eraseFlashTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3port Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3portTb4b4b4) Tff7b72returnTb4b4b4;

Tff7b72const Tb4b4b4{ Te6edf3usbVendorId Tb4b4b4} Tff7b72= Te6edf3portTb4b4b4.Te6edf3getInfoTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3NRF52_VIDSTb4b4b4.Te6edf3includesTb4b4b4(Te6edf3usbVendorIdTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3eraseNrf52FlashTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72returnTb4b4b4;
Tb4b4b4}

Tff7b72if Tb4b4b4(Tff7b72!Tffa657windowTb4b4b4.Te6edf3ESPLoaderTb4b4b4) Tb4b4b4{ Te6edf3alertTb4b4b4(Ta5d6ff'esptool-js not loaded'Tb4b4b4)Tb4b4b4; Tff7b72returnTb4b4b4; Tb4b4b4}

Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff0Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3clearLogTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.erasing'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Erasing flash...'Tb4b4b4)Tb4b4b4;

Tff7b72let Te6edf3transportTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3onLine Tff7b72= Tb4b4b4(Te6edf3lineTb4b4b4) Tb4b4b4=> Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Te6edf3lineTb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3esploaderTb4b4b4, Te6edf3chipTb4b4b4;
Tff7b72try Tb4b4b4{
Tb4b4b4(Tb4b4b4{ Te6edf3transportTb4b4b4, Te6edf3esploaderTb4b4b4, Te6edf3chip Tb4b4b4} Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3espConnectTb4b4b4(Te6edf3portTb4b4b4, Te6edf3onLineTb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72&& Ta5d6ff/open|port|access/iTb4b4b4.Te6edf3testTb4b4b4(Te6edf3eTb4b4b4.Te6edf3messageTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Ta5d6ff`Ta5d6ffPort error: Tffd700${Te6edf3eTb4b4b4.Te6edf3messageTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Attempting bootloader reset...'Tb4b4b4)Tb4b4b4;
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3enterBootloaderTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Retrying connection...'Tb4b4b4)Tb4b4b4;
Tb4b4b4(Tb4b4b4{ Te6edf3transportTb4b4b4, Te6edf3esploaderTb4b4b4, Te6edf3chip Tb4b4b4} Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3espConnectTb4b4b4(Te6edf3portTb4b4b4, Te6edf3onLineTb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72throw Te6edf3eTb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffChip: Tffd700${Te6edf3chipTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3esploaderTb4b4b4.Te6edf3eraseFlashTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Flash erased'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.erased'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3releaseEspTransportTb4b4b4(Te6edf3transportTb4b4b4, Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3disconnectPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4; Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff0Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,

T8b949e// nRF52 erase path used by eraseFlash() above. Flashes the universal
T8b949e// eraser app; the device must already be in the Adafruit bootloader
T8b949e// before this is called β€” use the "Enter DFU Mode" advanced tool
T8b949e// (or a manual double-press RST as a fallback).
Tff7b72async Te6edf3eraseNrf52FlashTb4b4b4(Te6edf3portTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff0Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3clearLogTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.erasing'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Erasing nRF52 internal filesystem via universal eraser...'Tb4b4b4)Tb4b4b4;

Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3eraseBlob Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3fetchFirmwareBlobTb4b4b4(Te6edf3NRF52_ERASER_ZIPTb4b4b4)Tb4b4b4;
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3doNrf52FlashTb4b4b4(Te6edf3portTb4b4b4, Te6edf3eraseBlobTb4b4b4, Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.erasing'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Flash erased'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.erased'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3disconnectPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4; Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3flashProgress Tff7b72= T79c0ff0Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3detectRNodeTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.detecting'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Detecting RNode...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ver Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getFirmwareVersionTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffRNode detected β€” RNode_Firmware Tffd700${Te6edf3verTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff`Ta5d6ffRNode detected (fw vTffd700${Te6edf3verTffd700}Ta5d6ff)Ta5d6ff`Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3wipeEepromTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3confirmTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'confirm.wipe'Tb4b4b4)Tb4b4b4)Tb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72const Te6edf3port Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3portTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3clearLogTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.wiping'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Wiping EEPROM (~30s)...'Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3rnode Tff7b72= Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3wipeRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3resetTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'EEPROM wiped!'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.wiped'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4; Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4; Tb4b4b4}
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3rebootRNodeTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.rebooting'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Rebooting RNode...'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3resetTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Reboot command sent'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.reboot_sent'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3manualProvisionTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3device Tff7b72= Tff7b72thisTb4b4b4.Te6edf3selectedDeviceTb4b4b4;
Tff7b72const Te6edf3variant Tff7b72= Tff7b72thisTb4b4b4.Te6edf3selectedVariantTb4b4b4;
Tff7b72const Te6edf3port Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3portTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3clearLogTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.connecting'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Connecting to RNode...'Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3rnode Tff7b72= Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ok Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3okTb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'Device not detected as RNode'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ver Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getFirmwareVersionTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffRNode detected β€” RNode_Firmware Tffd700${Te6edf3verTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;

Tff7b72const Te6edf3eeprom Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3isProvisionedTb4b4b4(Te6edf3eepromTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3confirmTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'confirm.provision'Tb4b4b4)Tb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72returnTb4b4b4;
Tb4b4b4}
Tb4b4b4}

Tff7b72const Te6edf3productId Tff7b72= Te6edf3deviceTb4b4b4.Te6edf3product_idTb4b4b4;
Tff7b72const Te6edf3modelId Tff7b72= Te6edf3variantTb4b4b4.Te6edf3mapped_model_id Tff7b72?? Te6edf3variantTb4b4b4.Te6edf3model_idTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff`Ta5d6ffProvisioning EEPROM (Product: 0xTffd700${Te6edf3productIdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tffd700}Ta5d6ff, Model: 0xTffd700${Te6edf3modelIdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tffd700}Ta5d6ff)...Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.provisioning'Tb4b4b4)Tb4b4b4;
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3provisionDeviceTb4b4b4(Te6edf3rnodeTb4b4b4, Te6edf3productIdTb4b4b4, Te6edf3modelIdTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'EEPROM provisioned'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.provisioned'Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3resetTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4; Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4; Tb4b4b4}
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3manualSetHashTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3port Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3portTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3clearLogTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.connecting'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Connecting to RNode...'Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3rnode Tff7b72= Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ok Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3okTb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'Device not detected as RNode'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ver Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getFirmwareVersionTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffRNode detected β€” RNode_Firmware Tffd700${Te6edf3verTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reading firmware hash from device...'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.hashing'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3hash Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getFirmwareHashTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffHash: Tffd700${Te6edf3UtilsTb4b4b4.Te6edf3bytesToHexTb4b4b4(Te6edf3hashTb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setFirmwareHashTb4b4b4(Te6edf3hashTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(T79c0ff30000Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Firmware hash set'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.hash_set'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4; Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4; Tb4b4b4}
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3dumpEepromTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.reading_eeprom'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reading EEPROM...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ver Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getFirmwareVersionTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffRNode detected β€” RNode_Firmware Tffd700${Te6edf3verTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;

Tff7b72const Te6edf3e Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'EEPROM contents:'Tb4b4b4)Tb4b4b4;

Tff7b72const Te6edf3productId Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_PRODUCTTb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3modelId Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_MODELTb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3provisioned Tff7b72= Te6edf3ROMTb4b4b4.Te6edf3isProvisionedTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4;

T8b949e// Product name lookup
Tff7b72const Te6edf3matchingDevices Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3grp Tff7b72of Te6edf3DEVICE_GROUPSTb4b4b4)
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3dev Tff7b72of Te6edf3grpTb4b4b4.Te6edf3devicesTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3devTb4b4b4.Te6edf3product_id Tff7b72=== Te6edf3productIdTb4b4b4) Te6edf3matchingDevicesTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3devTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3productLabel Tff7b72= Te6edf3matchingDevicesTb4b4b4.Te6edf3length
Tff7b72? Tb4b4b4[Tb4b4b4...Tff7b72new Tffa657SetTb4b4b4(Te6edf3matchingDevicesTb4b4b4.Te6edf3mapTb4b4b4(Te6edf3d Tb4b4b4=> Te6edf3dTb4b4b4.Te6edf3nameTb4b4b4)Tb4b4b4)Tb4b4b4]Tb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff' / 'Tb4b4b4)
Tff7b72: Ta5d6ff'unknown'Tb4b4b4;

T8b949e// Model β†’ frequency band lookup within matching devices
Tff7b72const Te6edf3freqSet Tff7b72= Tff7b72new Tffa657SetTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3dev Tff7b72of Te6edf3matchingDevicesTb4b4b4)
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3v Tff7b72of Te6edf3devTb4b4b4.Te6edf3variantsTb4b4b4)
Tff7b72if Tb4b4b4(Tb4b4b4(Te6edf3vTb4b4b4.Te6edf3mapped_model_id Tff7b72?? Te6edf3vTb4b4b4.Te6edf3model_idTb4b4b4) Tff7b72=== Te6edf3modelIdTb4b4b4)
Te6edf3freqSetTb4b4b4.Te6edf3addTb4b4b4(Te6edf3vTb4b4b4.Te6edf3nameTb4b4b4.Te6edf3splitTb4b4b4(Ta5d6ff' β€” 'Tb4b4b4)Tb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3modelLabel Tff7b72= Te6edf3freqSetTb4b4b4.Te6edf3size Tff7b72? Tb4b4b4[Tb4b4b4...Te6edf3freqSetTb4b4b4]Tb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff' / 'Tb4b4b4) Tff7b72: Ta5d6ff'unknown'Tb4b4b4;

T8b949e// Serial and made as human values
Tff7b72const Te6edf3read32BE Tff7b72= Tb4b4b4(Te6edf3offTb4b4b4) Tb4b4b4=> Tff7b72new Tffa657DataViewTb4b4b4(Tff7b72new Tffa657Uint8ArrayTb4b4b4(Tb4b4b4[Te6edf3eTb4b4b4[Te6edf3offTb4b4b4]Tb4b4b4,Te6edf3eTb4b4b4[Te6edf3offTff7b72+T79c0ff1Tb4b4b4]Tb4b4b4,Te6edf3eTb4b4b4[Te6edf3offTff7b72+T79c0ff2Tb4b4b4]Tb4b4b4,Te6edf3eTb4b4b4[Te6edf3offTff7b72+T79c0ff3Tb4b4b4]Tb4b4b4]Tb4b4b4)Tb4b4b4.Te6edf3bufferTb4b4b4)Tb4b4b4.Te6edf3getUint32Tb4b4b4(T79c0ff0Tb4b4b4,Tff7b72falseTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3serialVal Tff7b72= Te6edf3read32BETb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3ADDR_SERIALTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3madeVal Tff7b72= Te6edf3read32BETb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3ADDR_MADETb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3madeStr Tff7b72= Te6edf3madeVal Tff7b72> T79c0ff0
Tff7b72? Tff7b72new Tffa657DateTb4b4b4(Te6edf3madeVal Tff7b72* T79c0ff1000Tb4b4b4)Tb4b4b4.Te6edf3toISOStringTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff'T'Tb4b4b4,Ta5d6ff' 'Tb4b4b4)Tb4b4b4.Te6edf3sliceTb4b4b4(T79c0ff0Tb4b4b4,T79c0ff16Tb4b4b4) Tff7b72+ Ta5d6ff' UTC'
Tff7b72: Ta5d6ff'unset'Tb4b4b4;

Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffProduct: 0xTffd700${Te6edf3productIdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff2Tb4b4b4,Ta5d6ff'0'Tb4b4b4)Tffd700}Ta5d6ff Tffd700${Te6edf3productLabelTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffModel: 0xTffd700${Te6edf3modelIdTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff2Tb4b4b4,Ta5d6ff'0'Tb4b4b4)Tffd700}Ta5d6ff Tffd700${Te6edf3modelLabelTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffHW Rev: Tffd700${Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_HW_REVTb4b4b4]Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffSerial: Tffd700${Te6edf3serialValTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffMade: Tffd700${Te6edf3madeStrTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffChecksum: Tffd700${Te6edf3provisioned Tff7b72? Ta5d6ff'valid' Tff7b72: Ta5d6ff'invalid'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffInfo Lock: 0xTffd700${Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_INFO_LOCKTb4b4b4]Tb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff2Tb4b4b4,Ta5d6ff'0'Tb4b4b4)Tffd700}Ta5d6ff Tffd700${Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_INFO_LOCKTb4b4b4] Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3INFO_LOCK_BYTE Tff7b72? Ta5d6ff'(locked)' Tff7b72: Ta5d6ff'(unlocked)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffConf OK: 0xTffd700${Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_OKTb4b4b4]Tb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff2Tb4b4b4,Ta5d6ff'0'Tb4b4b4)Tffd700}Ta5d6ff Tffd700${Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_OKTb4b4b4] Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3CONF_OK_BYTE Tff7b72? Ta5d6ff'(ok)' Tff7b72: Ta5d6ff'(not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffProvisioned: Tffd700${Te6edf3provisioned Tff7b72? Ta5d6ff'yes' Tff7b72: Ta5d6ff'no'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;

T8b949e// Raw hex dump β€” 16 bytes per line
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Raw hex dump:'Tb4b4b4)Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3i Tff7b72= T79c0ff0Tb4b4b4; Te6edf3i Tff7b72< Te6edf3eTb4b4b4.Te6edf3lengthTb4b4b4; Te6edf3i Tff7b72+= T79c0ff16Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3slice Tff7b72= Tffa657ArrayTb4b4b4.Tff7b72fromTb4b4b4(Tb4b4b4{Te6edf3lengthTff7b72: Tffa657MathTb4b4b4.Te6edf3minTb4b4b4(T79c0ff16Tb4b4b4, Te6edf3eTb4b4b4.Te6edf3lengthTff7b72-Te6edf3iTb4b4b4)Tb4b4b4}Tb4b4b4, Tb4b4b4(Te6edf3_Tb4b4b4,Te6edf3jTb4b4b4) Tb4b4b4=> Te6edf3eTb4b4b4[Te6edf3iTff7b72+Te6edf3jTb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3hex Tff7b72= Te6edf3sliceTb4b4b4.Te6edf3mapTb4b4b4(Te6edf3b Tb4b4b4=> Te6edf3bTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff2Tb4b4b4,Ta5d6ff'0'Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff' 'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3addr Tff7b72= Te6edf3iTb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff4Tb4b4b4,Ta5d6ff'0'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Tffd700${Te6edf3addrTffd700}Ta5d6ff: Tffd700${Te6edf3hexTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tb4b4b4}

Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.dumped'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Generic connect-act-disconnect helper ─────────────────
T8b949e// Node configuration (radio/display/wifi/ethernet/bluetooth/misc/RTC) all
T8b949e// route through here - it's the one chokepoint that needed to learn about
T8b949e// the network transport, not each of the ~20 read/apply methods above.
T8b949e// Flashing/erase/DFU are NOT routed through this and stay serial-only,
T8b949e// since those need real USB bootloader access with no network equivalent.
Tff7b72async Te6edf3withRNodeTb4b4b4(Te6edf3stepTb4b4b4, Te6edf3fnTb4b4b4, Tb4b4b4{ Te6edf3append Tff7b72= Tff7b72false Tb4b4b4} Tff7b72= Tb4b4b4{Tb4b4b4}Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3usingNetwork Tff7b72= Tff7b72!Tff7b72!Tff7b72thisTb4b4b4.Te6edf3connectedNetworkUrlTb4b4b4;
Tff7b72let Te6edf3port Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3usingNetworkTb4b4b4) Tb4b4b4{
Te6edf3port Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3portTb4b4b4) Tff7b72returnTb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3appendTb4b4b4) Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3clearLogTb4b4b4(Tb4b4b4)Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff''Tb4b4b4; Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Te6edf3stepTb4b4b4;
T8b949e// Declared outside the inner try so the outer catch can close it too -
T8b949e// unlike a serial port, closing port.close() is a no-op for the
T8b949e// network path (port stays null there), so a failed detect()/fn()
T8b949e// would otherwise leak the WebSocket and leave the device's
T8b949e// single-client slot occupied.
Tff7b72let Te6edf3rnode Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3rnode Tff7b72= Te6edf3usingNetwork
Tff7b72? Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromWebSocketTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedNetworkUrlTb4b4b4)
Tff7b72: Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3usingNetworkTb4b4b4) Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3connectedNetworkUrl Tff7b72= Tff7b72nullTb4b4b4; Tb4b4b4}
Tff7b72else Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3connectedPort Tff7b72= Tff7b72nullTb4b4b4; Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3connectedPlatform Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72throw Te6edf3eTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3ok Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3okTb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'Device not detected as RNode'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3fnTb4b4b4(Te6edf3rnodeTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4{ Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4} Tb4b4b4}
Tff7b72else Tff7b72if Tb4b4b4(Te6edf3portTb4b4b4) Tb4b4b4{ Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4} Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4; Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4; Tb4b4b4}
Tb4b4b4}Tb4b4b4,

T8b949e// ── Tabs ──────────────────────────────────────────────────
Te6edf3selectTabTb4b4b4(Te6edf3tabTb4b4b4, Te6edf3append Tff7b72= Tff7b72falseTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3tab Tff7b72=== Ta5d6ff'wifi' Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3wifiSupportedTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3tab Tff7b72=== Ta5d6ff'ethernet' Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3connectedDevice Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3ethernetSupportedTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3tab Tff7b72=== Ta5d6ff'misc' Tff7b72&& Tff7b72!Tff7b72thisTb4b4b4.Te6edf3miscSupportedTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3cfgTab Tff7b72= Te6edf3tabTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3connectedDeviceTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3tab Tff7b72=== Ta5d6ff'radio'Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3readRadioTb4b4b4(Te6edf3appendTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3tab Tff7b72=== Ta5d6ff'display'Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3readDisplaySettingsTb4b4b4(Te6edf3appendTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3tab Tff7b72=== Ta5d6ff'wifi'Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3readWifiTb4b4b4(Te6edf3appendTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3tab Tff7b72=== Ta5d6ff'ethernet'Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3readEthernetTb4b4b4(Te6edf3appendTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3tab Tff7b72=== Ta5d6ff'bluetooth'Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3readBluetoothTb4b4b4(Te6edf3appendTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3tab Tff7b72=== Ta5d6ff'misc'Tb4b4b4) Tff7b72thisTb4b4b4.Te6edf3readMiscTb4b4b4(Te6edf3appendTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,

T8b949e// ── Radio ─────────────────────────────────────────────────
Tff7b72async Te6edf3readRadioTb4b4b4(Te6edf3append Tff7b72= Tff7b72falseTb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.reading_radio'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reading radio settings...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3e Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3freq Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getFrequencyTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3bw Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getBandwidthTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3pwr Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getTxPowerTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3sf Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getSpreadingFactorTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3cr Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getCodingRateTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3tncEnabled Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_OKTb4b4b4] Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3CONF_OK_BYTETb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3radioFreqMhz Tff7b72= Te6edf3freq Tff7b72> T79c0ff0 Tff7b72? Tb4b4b4(Te6edf3freq Tff7b72/ T79c0ff1e6Tb4b4b4)Tb4b4b4.Te6edf3toFixedTb4b4b4(T79c0ff6Tb4b4b4)Tb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/\.?0+$/Tb4b4b4, Ta5d6ff''Tb4b4b4) Tff7b72: Ta5d6ff'868.825'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3radioBwHz Tff7b72= Te6edf3bw Tff7b72> T79c0ff0 Tff7b72? Te6edf3bw Tff7b72: T79c0ff125000Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3radioTxPower Tff7b72= Te6edf3pwr Tff7b72< T79c0ff255 Tff7b72? Te6edf3pwr Tff7b72: T79c0ff17Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3radioSf Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tncEnabled Tff7b72&& Te6edf3sf Tff7b72>= T79c0ff7 Tff7b72? Te6edf3sf Tff7b72: T79c0ff10Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3radioCr Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tncEnabled Tff7b72&& Te6edf3cr Tff7b72>= T79c0ff5 Tff7b72? Te6edf3cr Tff7b72: T79c0ff7Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffTNC Mode: Tffd700${Tff7b72thisTb4b4b4.Te6edf3tncEnabled Tff7b72? Ta5d6ff'enabled' Tff7b72: Ta5d6ff'disabled'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffFreq: Tffd700${Te6edf3freq Tff7b72> T79c0ff0 Tff7b72? Tff7b72thisTb4b4b4.Te6edf3radioFreqMhz Tff7b72+ Ta5d6ff' MHz' Tff7b72: Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffBandwidth: Tffd700${Te6edf3bw Tff7b72> T79c0ff0 Tff7b72? Te6edf3bwTff7b72/T79c0ff1000 Tff7b72+ Ta5d6ff' kHz' Tff7b72: Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffTX Power: Tffd700${Te6edf3pwr Tff7b72< T79c0ff255 Tff7b72? Te6edf3pwr Tff7b72+ Ta5d6ff' dBm' Tff7b72: Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffSF: Tffd700${Te6edf3sf Tff7b72>= T79c0ff7 Tff7b72? Ta5d6ff'SF' Tff7b72+ Te6edf3sf Tff7b72: Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffCR: Tffd700${Te6edf3freq Tff7b72> T79c0ff0 Tff7b72? Ta5d6ff'CR4/' Tff7b72+ Te6edf3cr Tff7b72: Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.radio_read'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3append Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3applyRadioTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.applying_radio'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72const Te6edf3hz Tff7b72= Tffa657MathTb4b4b4.Te6edf3roundTb4b4b4(Tffa657parseFloatTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3radioFreqMhzTb4b4b4) Tff7b72* T79c0ff1e6Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3hz Tff7b72|| Tffa657isNaNTb4b4b4(Te6edf3hzTb4b4b4)Tb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'Invalid frequency'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'applying radio settings...'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setFrequencyTb4b4b4(Te6edf3hzTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setBandwidthTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3radioBwHzTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setTxPowerTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3radioTxPowerTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setSpreadingFactorTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3radioSfTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setCodingRateTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3radioCrTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3saveConfigTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3tncEnabled Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'radio settings applied and saved'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.radio_applied'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3enableTncTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.enabling_tnc'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'enabling TNC / Transport mode...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3hz Tff7b72= Tffa657MathTb4b4b4.Te6edf3roundTb4b4b4(Tffa657parseFloatTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3radioFreqMhzTb4b4b4) Tff7b72* T79c0ff1e6Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3hz Tff7b72|| Tffa657isNaNTb4b4b4(Te6edf3hzTb4b4b4)Tb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'Set a valid frequency before enabling TNC'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffFreq: Tffd700${Tff7b72thisTb4b4b4.Te6edf3radioFreqMhzTffd700}Ta5d6ff MHzTa5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffBandwidth: Tffd700${Tff7b72thisTb4b4b4.Te6edf3radioBwHz Tff7b72/ T79c0ff1000Tffd700}Ta5d6ff kHzTa5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffTX Power: Tffd700${Tff7b72thisTb4b4b4.Te6edf3radioTxPowerTffd700}Ta5d6ff dBmTa5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffSF: SFTffd700${Tff7b72thisTb4b4b4.Te6edf3radioSfTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffCR: CR4/Tffd700${Tff7b72thisTb4b4b4.Te6edf3radioCrTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setFrequencyTb4b4b4(Te6edf3hzTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setBandwidthTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3radioBwHzTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setTxPowerTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3radioTxPowerTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setSpreadingFactorTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3radioSfTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setCodingRateTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3radioCrTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setRadioStateTb4b4b4(Tff7b72trueTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff500Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3saveConfigTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3saveConfigTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'config saved, rebooting...'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff3000Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3resetTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3tncEnabled Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'TNC / Transport mode enabled'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.tnc_enabled'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3disableTncTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.disabling_tnc'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Disabling TNC / Transport mode...'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3deleteConfigTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff3000Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3resetTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3tncEnabled Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'TNC / Transport mode disabled'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.tnc_disabled'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Display ───────────────────────────────────────────────
Tff7b72async Te6edf3readDisplaySettingsTb4b4b4(Te6edf3append Tff7b72= Tff7b72falseTb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.reading_display'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reading display settings...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3e Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
T8b949e// Rotation: firmware treats 0xFF as "not configured β†’ default 0Β°"
Tff7b72const Te6edf3rawRot Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_DROTTb4b4b4] Tff7b72?? T79c0ff0xFFTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3dispRotation Tff7b72= Tb4b4b4(Te6edf3rawRot Tff7b72>= T79c0ff0 Tff7b72&& Te6edf3rawRot Tff7b72<= T79c0ff3Tb4b4b4) Tff7b72? Te6edf3rawRot Tff7b72: T79c0ff0Tb4b4b4;
T8b949e// Intensity: DSET is written on first boot; value is 0x03 (ESP32) or 0xFF (others) by default
Tff7b72thisTb4b4b4.Te6edf3dispIntensity Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_DSETTb4b4b4] Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3CONF_OK_BYTE
Tff7b72? Tb4b4b4(Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_DINTTb4b4b4] Tff7b72?? T79c0ff255Tb4b4b4) Tff7b72: T79c0ff255Tb4b4b4;
T8b949e// Bucket any historical continuous value (e.g. set before this board
T8b949e// had the 3-state picker) into the nearest of OFF/DIM/BRIGHT, mirroring
T8b949e// the same bucketing the on-device settings menu firmware uses.
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3oledDisplay Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3dispIntensity Tff7b72!== T79c0ff0 Tff7b72&& Tff7b72thisTb4b4b4.Te6edf3dispIntensity Tff7b72!== T79c0ff255Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3dispIntensity Tff7b72= T79c0ff1Tb4b4b4;
Tb4b4b4}
T8b949e// Timeout: only valid when BSET flag (0xB7) is set; otherwise blanking is disabled
Tff7b72thisTb4b4b4.Te6edf3dispTimeout Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_BSETTb4b4b4] Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3CONF_OK_BYTE
Tff7b72? Tb4b4b4(Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_DBLKTb4b4b4] Tff7b72?? T79c0ff0Tb4b4b4) Tff7b72: T79c0ff0Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffRotation: Tffd700${Tff7b72thisTb4b4b4.Te6edf3dispRotation Tff7b72* T79c0ff90Tffd700}Ta5d6ffΒ°Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffIntensity: Tffd700${Tff7b72thisTb4b4b4.Te6edf3dispIntensityTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffTimeout: Tffd700${Tff7b72thisTb4b4b4.Te6edf3dispTimeout Tff7b72=== T79c0ff0 Tff7b72? Ta5d6ff'always on' Tff7b72: Tff7b72thisTb4b4b4.Te6edf3dispTimeout Tff7b72+ Ta5d6ff's'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Display settings loaded.'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.display_read'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3append Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3applyDisplayTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.applying_display'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'applying display settings...'Tb4b4b4)Tb4b4b4;
T8b949e// Rotation last: it's the only field that intentionally reboots the
T8b949e// device (drot_conf_save() only when the value actually changes),
T8b949e// so applying intensity/timeout first means they land before that
T8b949e// reboot. Small gaps between writes are cheap insurance against
T8b949e// nRF52's eeprom_update() (a full LittleFS close+reopen per byte)
T8b949e// being hit as a rapid back-to-back burst.
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setDisplayIntensityTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3dispIntensityTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff150Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setDisplayTimeoutTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3dispTimeoutTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff150Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setDisplayRotationTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3dispRotationTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'display settings applied and saved'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.display_applied'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3doReconditionDisplayTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3isReconditioningTb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.stopping_rcnd'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'stopping display reconditioning (reboot)...'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3resetTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3isReconditioning Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'rebooting device'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.device_reboot'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72returnTb4b4b4;
Tb4b4b4}
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.reconditioning'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'starting display reconditioning...'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3reconditionDisplayTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3isReconditioning Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'reconditioning command sent'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.display_rcnd'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── WiFi ──────────────────────────────────────────────────
T8b949e// ── WiFi ─────────────────────────────────────────────────
Tff7b72async Te6edf3readWifiTb4b4b4(Te6edf3append Tff7b72= Tff7b72falseTb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.reading_wifi'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reading WiFi settings...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3e Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3c Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getWifiConfigTb4b4b4(Tb4b4b4)Tb4b4b4;

T8b949e// Mode and channel from main EEPROM
Tff7b72const Te6edf3rawMode Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_WIFITb4b4b4] Tff7b72?? T79c0ff0Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3wifiMode Tff7b72= Tb4b4b4(Te6edf3rawMode Tff7b72=== T79c0ff0x01 Tff7b72|| Te6edf3rawMode Tff7b72=== T79c0ff0x02Tb4b4b4) Tff7b72? Te6edf3rawMode Tff7b72: T79c0ff0Tb4b4b4;
Tff7b72const Te6edf3rawChn Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_WCHNTb4b4b4] Tff7b72?? T79c0ff0Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3wifiChannel Tff7b72= Tb4b4b4(Te6edf3rawChn Tff7b72>= T79c0ff1 Tff7b72&& Te6edf3rawChn Tff7b72<= T79c0ff13Tb4b4b4) Tff7b72? Te6edf3rawChn Tff7b72: T79c0ff1Tb4b4b4;

Tff7b72if Tb4b4b4(Te6edf3cTb4b4b4.Te6edf3length Tff7b72>= T79c0ff4Tb4b4b4) Tb4b4b4{
T8b949e// SSID: 32 bytes at 0x00, null/0xFF terminated
Tff7b72const Te6edf3ssidBytes Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3i Tff7b72= Te6edf3ROMTb4b4b4.Te6edf3CFG_SSIDTb4b4b4; Te6edf3i Tff7b72< Te6edf3ROMTb4b4b4.Te6edf3CFG_SSID Tff7b72+ T79c0ff32Tb4b4b4; Te6edf3iTff7b72++Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3cTb4b4b4[Te6edf3iTb4b4b4] Tff7b72|| Te6edf3cTb4b4b4[Te6edf3iTb4b4b4] Tff7b72=== T79c0ff0xFFTb4b4b4) Tff7b72breakTb4b4b4;
Te6edf3ssidBytesTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3cTb4b4b4[Te6edf3iTb4b4b4]Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3wifiSsid Tff7b72= Tff7b72new Te6edf3TextDecoderTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3decodeTb4b4b4(Tff7b72new Tffa657Uint8ArrayTb4b4b4(Te6edf3ssidBytesTb4b4b4)Tb4b4b4)Tb4b4b4;

T8b949e// PSK: 32 bytes at 0x21, null/0xFF terminated
Tff7b72const Te6edf3pskBytes Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3i Tff7b72= Te6edf3ROMTb4b4b4.Te6edf3CFG_PSKTb4b4b4; Te6edf3i Tff7b72< Te6edf3ROMTb4b4b4.Te6edf3CFG_PSK Tff7b72+ T79c0ff32Tb4b4b4; Te6edf3iTff7b72++Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3cTb4b4b4[Te6edf3iTb4b4b4] Tff7b72|| Te6edf3cTb4b4b4[Te6edf3iTb4b4b4] Tff7b72=== T79c0ff0xFFTb4b4b4) Tff7b72breakTb4b4b4;
Te6edf3pskBytesTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3cTb4b4b4[Te6edf3iTb4b4b4]Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3wifiPsk Tff7b72= Tff7b72new Te6edf3TextDecoderTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3decodeTb4b4b4(Tff7b72new Tffa657Uint8ArrayTb4b4b4(Te6edf3pskBytesTb4b4b4)Tb4b4b4)Tb4b4b4;

T8b949e// IP: 4 bytes at 0x42 β€” 0xFF = never written, 0x00 = explicitly cleared
Tff7b72const Te6edf3ipBytes Tff7b72= Te6edf3cTb4b4b4.Te6edf3length Tff7b72> Te6edf3ROMTb4b4b4.Te6edf3CFG_IP Tff7b72+ T79c0ff3
Tff7b72? Tb4b4b4[Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_IPTb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_IPTff7b72+T79c0ff1Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_IPTff7b72+T79c0ff2Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_IPTff7b72+T79c0ff3Tb4b4b4]Tb4b4b4] Tff7b72: Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3wifiIp Tff7b72= Tb4b4b4(Te6edf3ipBytes Tff7b72&& Te6edf3ipBytesTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72!== T79c0ff0xFF Tff7b72&& Te6edf3ipBytesTb4b4b4.Te6edf3someTb4b4b4(Te6edf3b Tb4b4b4=> Te6edf3b Tff7b72!== T79c0ff0Tb4b4b4)Tb4b4b4)
Tff7b72? Te6edf3ipBytesTb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff'.'Tb4b4b4) Tff7b72: Ta5d6ff''Tb4b4b4;

T8b949e// Netmask: 4 bytes at 0x46
Tff7b72const Te6edf3nmBytes Tff7b72= Te6edf3cTb4b4b4.Te6edf3length Tff7b72> Te6edf3ROMTb4b4b4.Te6edf3CFG_NM Tff7b72+ T79c0ff3
Tff7b72? Tb4b4b4[Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_NMTb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_NMTff7b72+T79c0ff1Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_NMTff7b72+T79c0ff2Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_NMTff7b72+T79c0ff3Tb4b4b4]Tb4b4b4] Tff7b72: Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3wifiNm Tff7b72= Tb4b4b4(Te6edf3nmBytes Tff7b72&& Te6edf3nmBytesTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72!== T79c0ff0xFF Tff7b72&& Te6edf3nmBytesTb4b4b4.Te6edf3someTb4b4b4(Te6edf3b Tb4b4b4=> Te6edf3b Tff7b72!== T79c0ff0Tb4b4b4)Tb4b4b4)
Tff7b72? Te6edf3nmBytesTb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff'.'Tb4b4b4) Tff7b72: Ta5d6ff''Tb4b4b4;

T8b949e// Gateway: 4 bytes at 0x52
Tff7b72const Te6edf3gwBytes Tff7b72= Te6edf3cTb4b4b4.Te6edf3length Tff7b72> Te6edf3ROMTb4b4b4.Te6edf3CFG_GW Tff7b72+ T79c0ff3
Tff7b72? Tb4b4b4[Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_GWTb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_GWTff7b72+T79c0ff1Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_GWTff7b72+T79c0ff2Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_GWTff7b72+T79c0ff3Tb4b4b4]Tb4b4b4] Tff7b72: Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3wifiGw Tff7b72= Tb4b4b4(Te6edf3gwBytes Tff7b72&& Te6edf3gwBytesTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72!== T79c0ff0xFF Tff7b72&& Te6edf3gwBytesTb4b4b4.Te6edf3someTb4b4b4(Te6edf3b Tb4b4b4=> Te6edf3b Tff7b72!== T79c0ff0Tb4b4b4)Tb4b4b4)
Tff7b72? Te6edf3gwBytesTb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff'.'Tb4b4b4) Tff7b72: Ta5d6ff''Tb4b4b4;

T8b949e// DNS: 4 bytes at 0x56
Tff7b72const Te6edf3dnsBytes Tff7b72= Te6edf3cTb4b4b4.Te6edf3length Tff7b72> Te6edf3ROMTb4b4b4.Te6edf3CFG_DNS Tff7b72+ T79c0ff3
Tff7b72? Tb4b4b4[Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_DNSTb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_DNSTff7b72+T79c0ff1Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_DNSTff7b72+T79c0ff2Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_DNSTff7b72+T79c0ff3Tb4b4b4]Tb4b4b4] Tff7b72: Tff7b72nullTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3wifiDns Tff7b72= Tb4b4b4(Te6edf3dnsBytes Tff7b72&& Te6edf3dnsBytesTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72!== T79c0ff0xFF Tff7b72&& Te6edf3dnsBytesTb4b4b4.Te6edf3someTb4b4b4(Te6edf3b Tb4b4b4=> Te6edf3b Tff7b72!== T79c0ff0Tb4b4b4)Tb4b4b4)
Tff7b72? Te6edf3dnsBytesTb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff'.'Tb4b4b4) Tff7b72: Ta5d6ff''Tb4b4b4;
Tb4b4b4}

Tff7b72const Te6edf3modeLabel Tff7b72= Tb4b4b4[Ta5d6ff'Off'Tb4b4b4, Ta5d6ff'Station'Tb4b4b4, Ta5d6ff'AP'Tb4b4b4]Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3wifiModeTb4b4b4] Tff7b72?? Ta5d6ff'Unknown'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffMode: Tffd700${Te6edf3modeLabelTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffChannel: Tffd700${Tff7b72thisTb4b4b4.Te6edf3wifiChannelTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffSSID: Tffd700${Tff7b72thisTb4b4b4.Te6edf3wifiSsid Tff7b72|| Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffIP: Tffd700${Tff7b72thisTb4b4b4.Te6edf3wifiIp Tff7b72|| Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffNetmask: Tffd700${Tff7b72thisTb4b4b4.Te6edf3wifiNm Tff7b72|| Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffGateway: Tffd700${Tff7b72thisTb4b4b4.Te6edf3wifiGw Tff7b72|| Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffDNS: Tffd700${Tff7b72thisTb4b4b4.Te6edf3wifiDns Tff7b72|| Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'WiFi settings loaded.'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.wifi_read'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3append Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3applyWifiTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.applying_wifi'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff`Ta5d6ffsetting wifi mode: Tffd700${Tb4b4b4[Ta5d6ff'off'Tb4b4b4, Ta5d6ff'station'Tb4b4b4, Ta5d6ff'AP'Tb4b4b4]Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3wifiModeTb4b4b4]Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiModeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiModeTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiMode Tff7b72> T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiSsidTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiSsidTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiPskTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiPsk Tff7b72|| Tff7b72nullTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiChannelTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiChannelTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiIpTb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiIpTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiIpTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiNmTb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiNmTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiNmTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiGwTb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiGwTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiGwTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiDnsTb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiDnsTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3wifiDnsTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3saveConfigTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'wifi settings applied and saved'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.wifi_applied'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3clearWifiTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.clearing_wifi'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'clearing wifi settings...'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiModeTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiSsidTb4b4b4(Ta5d6ff''Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiPskTb4b4b4(Tff7b72nullTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiChannelTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiIpTb4b4b4(Ta5d6ff'0.0.0.0'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiNmTb4b4b4(Ta5d6ff'0.0.0.0'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiGwTb4b4b4(Ta5d6ff'0.0.0.0'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setWifiDnsTb4b4b4(Ta5d6ff'0.0.0.0'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3wifiMode Tff7b72= T79c0ff0Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3wifiSsid Tff7b72= Ta5d6ff''Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3wifiPsk Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3wifiChannel Tff7b72= T79c0ff1Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3wifiIp Tff7b72= Ta5d6ff''Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3wifiNm Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3wifiGw Tff7b72= Ta5d6ff''Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3wifiDns Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'wifi settings cleared'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.wifi_cleared'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

T8b949e// ── Ethernet ──────────────────────────────────────────────
Tff7b72async Te6edf3readEthernetTb4b4b4(Te6edf3append Tff7b72= Tff7b72falseTb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.reading_ethernet'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reading Ethernet settings...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3e Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3c Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getWifiConfigTb4b4b4(Tb4b4b4)Tb4b4b4;

Tff7b72const Te6edf3rawSpeed Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_ETHSPDTb4b4b4] Tff7b72?? T79c0ff0xFFTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3ethSpeed Tff7b72= Tb4b4b4(Te6edf3rawSpeed Tff7b72<= Te6edf3ROMTb4b4b4.Te6edf3ETH_SPEED_OFFTb4b4b4) Tff7b72? Te6edf3rawSpeed Tff7b72: Te6edf3ROMTb4b4b4.Te6edf3ETH_SPEED_AUTOTb4b4b4;

Tff7b72if Tb4b4b4(Te6edf3cTb4b4b4.Te6edf3length Tff7b72> Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_NM Tff7b72+ T79c0ff3Tb4b4b4) Tb4b4b4{
T8b949e// IP/Netmask: 4 bytes each β€” 0xFF = never written, 0x00 = explicitly cleared
Tff7b72const Te6edf3ipBytes Tff7b72= Tb4b4b4[Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_IPTb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_IPTff7b72+T79c0ff1Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_IPTff7b72+T79c0ff2Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_IPTff7b72+T79c0ff3Tb4b4b4]Tb4b4b4]Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3ethIp Tff7b72= Tb4b4b4(Te6edf3ipBytesTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72!== T79c0ff0xFF Tff7b72&& Te6edf3ipBytesTb4b4b4.Te6edf3someTb4b4b4(Te6edf3b Tb4b4b4=> Te6edf3b Tff7b72!== T79c0ff0Tb4b4b4)Tb4b4b4) Tff7b72? Te6edf3ipBytesTb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff'.'Tb4b4b4) Tff7b72: Ta5d6ff''Tb4b4b4;

Tff7b72const Te6edf3nmBytes Tff7b72= Tb4b4b4[Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_NMTb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_NMTff7b72+T79c0ff1Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_NMTff7b72+T79c0ff2Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_NMTff7b72+T79c0ff3Tb4b4b4]Tb4b4b4]Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3ethNm Tff7b72= Tb4b4b4(Te6edf3nmBytesTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72!== T79c0ff0xFF Tff7b72&& Te6edf3nmBytesTb4b4b4.Te6edf3someTb4b4b4(Te6edf3b Tb4b4b4=> Te6edf3b Tff7b72!== T79c0ff0Tb4b4b4)Tb4b4b4) Tff7b72? Te6edf3nmBytesTb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff'.'Tb4b4b4) Tff7b72: Ta5d6ff''Tb4b4b4;
Tb4b4b4}

Tff7b72if Tb4b4b4(Te6edf3cTb4b4b4.Te6edf3length Tff7b72> Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_DNS Tff7b72+ T79c0ff3Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3gwBytes Tff7b72= Tb4b4b4[Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_GWTb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_GWTff7b72+T79c0ff1Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_GWTff7b72+T79c0ff2Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_GWTff7b72+T79c0ff3Tb4b4b4]Tb4b4b4]Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3ethGw Tff7b72= Tb4b4b4(Te6edf3gwBytesTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72!== T79c0ff0xFF Tff7b72&& Te6edf3gwBytesTb4b4b4.Te6edf3someTb4b4b4(Te6edf3b Tb4b4b4=> Te6edf3b Tff7b72!== T79c0ff0Tb4b4b4)Tb4b4b4) Tff7b72? Te6edf3gwBytesTb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff'.'Tb4b4b4) Tff7b72: Ta5d6ff''Tb4b4b4;

Tff7b72const Te6edf3dnsBytes Tff7b72= Tb4b4b4[Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_DNSTb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_DNSTff7b72+T79c0ff1Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_DNSTff7b72+T79c0ff2Tb4b4b4]Tb4b4b4, Te6edf3cTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3CFG_ETH_DNSTff7b72+T79c0ff3Tb4b4b4]Tb4b4b4]Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3ethDns Tff7b72= Tb4b4b4(Te6edf3dnsBytesTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72!== T79c0ff0xFF Tff7b72&& Te6edf3dnsBytesTb4b4b4.Te6edf3someTb4b4b4(Te6edf3b Tb4b4b4=> Te6edf3b Tff7b72!== T79c0ff0Tb4b4b4)Tb4b4b4) Tff7b72? Te6edf3dnsBytesTb4b4b4.Te6edf3joinTb4b4b4(Ta5d6ff'.'Tb4b4b4) Tff7b72: Ta5d6ff''Tb4b4b4;
Tb4b4b4}

Tff7b72const Te6edf3speedLabel Tff7b72= Tb4b4b4[Ta5d6ff'AUTO'Tb4b4b4, Ta5d6ff'100/FULL'Tb4b4b4, Ta5d6ff'100/HALF'Tb4b4b4, Ta5d6ff'10/FULL'Tb4b4b4, Ta5d6ff'10/HALF'Tb4b4b4, Ta5d6ff'OFF'Tb4b4b4]Tb4b4b4[Tff7b72thisTb4b4b4.Te6edf3ethSpeedTb4b4b4] Tff7b72?? Ta5d6ff'Unknown'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffSpeed: Tffd700${Te6edf3speedLabelTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffIP: Tffd700${Tff7b72thisTb4b4b4.Te6edf3ethIp Tff7b72|| Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffNetmask: Tffd700${Tff7b72thisTb4b4b4.Te6edf3ethNm Tff7b72|| Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffGateway: Tffd700${Tff7b72thisTb4b4b4.Te6edf3ethGw Tff7b72|| Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffDNS: Tffd700${Tff7b72thisTb4b4b4.Te6edf3ethDns Tff7b72|| Ta5d6ff'β€” (not set)'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Ethernet settings loaded.'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.ethernet_read'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3append Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3applyEthernetTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.applying_ethernet'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'applying ethernet settings...'Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3ethIpTb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setEthIpTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3ethIpTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3ethNmTb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setEthNmTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3ethNmTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3ethGwTb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setEthGwTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3ethGwTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3ethDnsTb4b4b4) Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setEthDnsTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3ethDnsTb4b4b4)Tb4b4b4;
T8b949e// Speed last: a changed value reboots the device immediately
T8b949e// (ethspd_conf_save(), firmware), so IP/Netmask must land first.
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setEthSpeedTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3ethSpeedTb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3saveConfigTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'ethernet settings applied and saved'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.ethernet_applied'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3clearEthernetTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.clearing_ethernet'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'clearing ethernet settings...'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setEthIpTb4b4b4(Ta5d6ff'0.0.0.0'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setEthNmTb4b4b4(Ta5d6ff'0.0.0.0'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setEthGwTb4b4b4(Ta5d6ff'0.0.0.0'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setEthDnsTb4b4b4(Ta5d6ff'0.0.0.0'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setEthSpeedTb4b4b4(Te6edf3ROMTb4b4b4.Te6edf3ETH_SPEED_AUTOTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3ethIp Tff7b72= Ta5d6ff''Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3ethNm Tff7b72= Ta5d6ff''Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3ethGw Tff7b72= Ta5d6ff''Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3ethDns Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3ethSpeed Tff7b72= Te6edf3ROMTb4b4b4.Te6edf3ETH_SPEED_AUTOTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'ethernet settings cleared'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.ethernet_cleared'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3readBluetoothTb4b4b4(Te6edf3append Tff7b72= Tff7b72falseTb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.reading_bt'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reading Bluetooth settings...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3e Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3btEnabled Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_BTTb4b4b4] Tff7b72=== Te6edf3ROMTb4b4b4.Te6edf3INFO_LOCK_BYTETb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3btPin Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3btPairing Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffBluetooth: Tffd700${Tff7b72thisTb4b4b4.Te6edf3btEnabled Tff7b72? Ta5d6ff'enabled' Tff7b72: Ta5d6ff'disabled'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Bluetooth settings loaded.'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.bt_read'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3append Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3setBluetoothTb4b4b4(Te6edf3enableTb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Te6edf3enable Tff7b72? Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.enabling_bt'Tb4b4b4) Tff7b72: Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.disabling_bt'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3enableTb4b4b4) Tb4b4b4{
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3enableBluetoothTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3btEnabled Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'bluetooth enabled'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3disableBluetoothTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3btEnabled Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3btPin Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3btPairing Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'bluetooth disabled'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Te6edf3enable Tff7b72? Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.bt_enabled'Tb4b4b4) Tff7b72: Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.bt_disabled'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
T8b949e// ── Misc (homebrew-only extras) ───────────────────────────
Tff7b72async Te6edf3readMiscTb4b4b4(Te6edf3append Tff7b72= Tff7b72falseTb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.reading_misc'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reading misc settings...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3e Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
T8b949e// Firmware default is ON: anything but SND_DISABLE_BYTE (0x00) means enabled
Tff7b72thisTb4b4b4.Te6edf3sndEnabled Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_SNDTb4b4b4] Tff7b72!== T79c0ff0x00Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffSound: Tffd700${Tff7b72thisTb4b4b4.Te6edf3sndEnabled Tff7b72? Ta5d6ff'enabled' Tff7b72: Ta5d6ff'disabled'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
T8b949e// 0x00/0xFF (erased EEPROM) both mean "unset" - fall back to the 11.0 board default
Tff7b72const Te6edf3rawVsr Tff7b72= Te6edf3eTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_CONF_VSRTb4b4b4]Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3vsenseDivider Tff7b72= Tb4b4b4(Te6edf3rawVsr Tff7b72!== Tff7b72undefined Tff7b72&& Te6edf3rawVsr Tff7b72!== T79c0ff0x00 Tff7b72&& Te6edf3rawVsr Tff7b72!== T79c0ff0xFFTb4b4b4) Tff7b72? Te6edf3rawVsr Tff7b72/ T79c0ff10.0 Tff7b72: T79c0ff11.0Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffVoltage divider: Tffd700${Tff7b72thisTb4b4b4.Te6edf3vsenseDividerTb4b4b4.Te6edf3toFixedTb4b4b4(T79c0ff1Tb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
T8b949e// Not every "Homebrew RNode" board has an RTC chip (only
T8b949e// MeshPoE-S3/MeshAdventurer-S3 do, but they collapse to the same
T8b949e// connected-device label) - CMD_TIME is #if HAS_RTC-gated in
T8b949e// firmware, so a board without one never responds at all. Give it
T8b949e// a short timeout and degrade quietly rather than failing the
T8b949e// whole misc-settings read over it.
Tff7b72try Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3rtcTime Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getTimeTb4b4b4(T79c0ff1500Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff`Ta5d6ffRTC time: Tffd700${Tff7b72thisTb4b4b4.Te6edf3rtcTimeDisplayTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3rtcTime Tff7b72= T79c0ff0Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Ta5d6ff'RTC: not present'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Misc settings loaded.'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.misc_read'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4, Tb4b4b4{ Te6edf3append Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3setSoundTb4b4b4(Te6edf3enableTb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Te6edf3enable Tff7b72? Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.enabling_snd'Tb4b4b4) Tff7b72: Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.disabling_snd'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setSoundTb4b4b4(Te6edf3enableTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3sndEnabled Tff7b72= Te6edf3enableTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffsound Tffd700${Te6edf3enable Tff7b72? Ta5d6ff'enabled' Tff7b72: Ta5d6ff'disabled'Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Te6edf3enable Tff7b72? Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.snd_enabled'Tb4b4b4) Tff7b72: Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.snd_disabled'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3applyMiscTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.applying_misc'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'applying misc settings...'Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setVsenseDividerTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3vsenseDividerTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffvoltage divider ratio set to Tffd700${Tff7b72thisTb4b4b4.Te6edf3vsenseDividerTb4b4b4.Te6edf3toFixedTb4b4b4(T79c0ff1Tb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.misc_applied'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3syncRtcFromBrowserTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.syncing_rtc'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'syncing RTC from browser clock...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3epoch Tff7b72= Tffa657MathTb4b4b4.Te6edf3floorTb4b4b4(Tffa657DateTb4b4b4.Te6edf3nowTb4b4b4(Tb4b4b4) Tff7b72/ T79c0ff1000Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3rtcTime Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3setTimeTb4b4b4(Te6edf3epochTb4b4b4)Tb4b4b4;
T8b949e// The firmware echoes back whatever it just read from the RTC chip -
T8b949e// a mismatch here means there's no RTC to write to, not a bad clock.
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3rtcTime Tff7b72=== Te6edf3epochTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffRTC synced: Tffd700${Tff7b72thisTb4b4b4.Te6edf3rtcTimeDisplayTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.rtc_synced'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Ta5d6ff'RTC sync failed β€” no RTC chip detected.'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.rtc_sync_failed'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3syncRtcFromNtpTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.syncing_rtc_ntp'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'syncing RTC from NTP...'Tb4b4b4)Tb4b4b4;
Tff7b72const Tb4b4b4{ Te6edf3statusTb4b4b4, Te6edf3epoch Tb4b4b4} Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3syncNtpTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3rtcTime Tff7b72= Te6edf3epochTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3status Tff7b72=== Te6edf3rnodeTb4b4b4.Te6edf3NTP_SYNC_OKTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffRTC synced: Tffd700${Tff7b72thisTb4b4b4.Te6edf3rtcTimeDisplayTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.rtc_synced'Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72const Te6edf3reasonKeys Tff7b72= Tb4b4b4{
Tb4b4b4[Te6edf3rnodeTb4b4b4.Te6edf3NTP_SYNC_ERR_NO_RTCTb4b4b4]Tff7b72: Ta5d6ff'rtc.ntp_err.no_rtc'Tb4b4b4,
Tb4b4b4[Te6edf3rnodeTb4b4b4.Te6edf3NTP_SYNC_ERR_NO_NETTb4b4b4]Tff7b72: Ta5d6ff'rtc.ntp_err.no_net'Tb4b4b4,
Tb4b4b4[Te6edf3rnodeTb4b4b4.Te6edf3NTP_SYNC_ERR_TIMEOUTTb4b4b4]Tff7b72: Ta5d6ff'rtc.ntp_err.timeout'Tb4b4b4,
Tb4b4b4[Te6edf3rnodeTb4b4b4.Te6edf3NTP_SYNC_ERR_RTC_WRITETb4b4b4]Tff7b72: Ta5d6ff'rtc.ntp_err.rtc_write'Tb4b4b4,
Tb4b4b4}Tb4b4b4;
Tff7b72const Te6edf3reason Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Te6edf3reasonKeysTb4b4b4[Te6edf3statusTb4b4b4] Tff7b72|| Ta5d6ff'rtc.ntp_err.unknown'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Ta5d6ff`Ta5d6ffNTP sync failed β€” Tffd700${Te6edf3reasonTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'status.rtc_sync_failed'Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3startPairingTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3usingNetwork Tff7b72= Tff7b72!Tff7b72!Tff7b72thisTb4b4b4.Te6edf3connectedNetworkUrlTb4b4b4;
Tff7b72let Te6edf3port Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3usingNetworkTb4b4b4) Tb4b4b4{
Te6edf3port Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3portTb4b4b4) Tff7b72returnTb4b4b4;
Tb4b4b4}
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3btPairing Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3btPin Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3clearLogTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff''Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'step.pairing'Tb4b4b4)Tb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3rnode Tff7b72= Te6edf3usingNetwork
Tff7b72? Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromWebSocketTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedNetworkUrlTb4b4b4)
Tff7b72: Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ok Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3okTb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'Device not detected as RNode'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Starting Bluetooth pairing...'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'info'Tb4b4b4, Ta5d6ff' > 'Tb4b4b4, Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'warn.bt_connect_phone'Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3pin Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3pairBluetoothTb4b4b4(T79c0ff30000Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3btPin Tff7b72= Te6edf3pinTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff`Ta5d6ffBluetooth pairing PIN: Tffd700${Te6edf3pinTffd700}Ta5d6ff`Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Ta5d6ff`Ta5d6ffBluetooth pairing PIN: Tffd700${Te6edf3pinTffd700}Ta5d6ff`Tb4b4b4;
Te6edf3setTimeoutTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3btPin Tff7b72= Ta5d6ff''Tb4b4b4; Tb4b4b4}Tb4b4b4, T79c0ff30000Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff20000Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3portTb4b4b4) Tb4b4b4{ Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4} Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3isWorking Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3btPairing Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3currentStep Tff7b72= Ta5d6ff''Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3toggleAutoRefreshTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3autoRefreshTb4b4b4) Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3autoRefresh Tff7b72= Tff7b72falseTb4b4b4; Tff7b72returnTb4b4b4; Tb4b4b4}
Tff7b72const Te6edf3usingNetwork Tff7b72= Tff7b72!Tff7b72!Tff7b72thisTb4b4b4.Te6edf3connectedNetworkUrlTb4b4b4;
Tff7b72let Te6edf3port Tff7b72= Tff7b72nullTb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3usingNetworkTb4b4b4) Tb4b4b4{
Te6edf3port Tff7b72= Tff7b72await Tff7b72thisTb4b4b4.Te6edf3requestPortTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3portTb4b4b4) Tff7b72returnTb4b4b4;
Tb4b4b4}
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3rnode Tff7b72= Te6edf3usingNetwork
Tff7b72? Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromWebSocketTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3connectedNetworkUrlTb4b4b4)
Tff7b72: Tff7b72await Te6edf3RNodeTb4b4b4.Te6edf3fromSerialPortTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3ok Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3detectTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3okTb4b4b4) Tff7b72throw Tff7b72new Tf85149ErrorTb4b4b4(Ta5d6ff'Device not detected as RNode'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3eeprom Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3productId Tff7b72= Te6edf3eepromTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_PRODUCTTb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3buf Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3readDisplayTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3screenImage Tff7b72= Te6edf3displayBufferToPngTb4b4b4(Te6edf3bufTb4b4b4, Te6edf3productIdTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3autoRefresh Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3_autoRefreshLoopTb4b4b4(Te6edf3rnodeTb4b4b4, Te6edf3productIdTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'err'Tb4b4b4, Ta5d6ff' βœ— 'Tb4b4b4, Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'error'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tffa657StringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72|| Te6edf3eTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3portTb4b4b4) Tb4b4b4{ Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3portTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3exTb4b4b4) Tb4b4b4{Tb4b4b4} Tb4b4b4}
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3_autoRefreshLoopTb4b4b4(Te6edf3rnodeTb4b4b4, Te6edf3productIdTb4b4b4) Tb4b4b4{
Tff7b72while Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3autoRefreshTb4b4b4) Tb4b4b4{
Tff7b72await Te6edf3UtilsTb4b4b4.Te6edf3sleepMillisTb4b4b4(T79c0ff1000Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3autoRefreshTb4b4b4) Tff7b72breakTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3buf Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3readDisplayTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3screenImage Tff7b72= Te6edf3displayBufferToPngTb4b4b4(Te6edf3bufTb4b4b4, Te6edf3productIdTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3autoRefresh Tff7b72= Tff7b72falseTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'warn'Tb4b4b4, Ta5d6ff' ! 'Tb4b4b4, Ta5d6ff'screen auto-refresh lost connection'Tb4b4b4)Tb4b4b4;
Tff7b72breakTb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tff7b72try Tb4b4b4{ Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)Tb4b4b4; Tb4b4b4} Tff7b72catchTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{Tb4b4b4}
Tb4b4b4}Tb4b4b4,

Tff7b72async Te6edf3readScreenTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72await Tff7b72thisTb4b4b4.Te6edf3withRNodeTb4b4b4(Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'adv.screen'Tb4b4b4)Tb4b4b4, Tff7b72async Tb4b4b4(Te6edf3rnodeTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'cmd'Tb4b4b4, Ta5d6ff'$ 'Tb4b4b4, Ta5d6ff'Reading screen...'Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3eeprom Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3getRomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3productId Tff7b72= Te6edf3eepromTb4b4b4[Te6edf3ROMTb4b4b4.Te6edf3ADDR_PRODUCTTb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3buf Tff7b72= Tff7b72await Te6edf3rnodeTb4b4b4.Te6edf3readDisplayTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3screenImage Tff7b72= Te6edf3displayBufferToPngTb4b4b4(Te6edf3bufTb4b4b4, Te6edf3productIdTb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3addLogTb4b4b4(Ta5d6ff'ok'Tb4b4b4, Ta5d6ff' βœ“ 'Tb4b4b4, Ta5d6ff'Screen captured'Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3statusType Tff7b72= Ta5d6ff'success'Tb4b4b4; Tff7b72thisTb4b4b4.Te6edf3statusMsg Tff7b72= Tff7b72thisTb4b4b4.Te6edf3tTb4b4b4(Ta5d6ff'screen.label'Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,

Tb4b4b4}
Tb4b4b4}Tb4b4b4)Tb4b4b4.Te6edf3mountTb4b4b4(Ta5d6ff'#app'Tb4b4b4)Tb4b4b4;
Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72bodyTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72htmlTb4b4b4>

Served by rngit 1.4.2 - Generated in 0.5s